<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/><meta name="exporter-version" content="Evernote Mac 9.1.3 (458534)"/><meta name="author" content="流星"/><meta name="created" content="2020-08-18 03:48:56 +0000"/><meta name="source" content="desktop.mac"/><meta name="updated" content="2020-10-10 13:52:00 +0000"/><meta name="content-class" content="yinxiang.markdown"/><title>ES6学习笔记</title></head><body><div style="font-size: 14px; margin: 0; padding: 0; width: 100%;"><h2 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 34px; border-bottom: 1px solid #dbdbdb; color: #333;">Reflect</h2>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;">    Reflect对象和Proxy对象一样，都是ES6为了操作对象而提供的API。
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">设计目的：</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;"><strong style="line-height: 160%; box-sizing: content-box; font-weight: 700;">1、替代Object。将Object上的原来的方法部署到Reflect上，并且之后新增方法也只部署到Reflect对象上。</strong><br/>
2、让之前Object某些方法返回结果更加合理。<br/>
3、让Object的操作变成函数行为。<br/>
<strong style="line-height: 160%; box-sizing: content-box; font-weight: 700;">4、与Proxy对象的方法一一对应（Proxy可以修改对象的行为，而Reflect可以找回对象的默认行为）。</strong></p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">静态方法：</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">1、Reflect.apply(target,thisArg,args)//绑定this对象后执行给定函数<br/>
2、Reflect.construct(target,args)//构造函数<br/>
3、Reflect.get(target,name,receiver)//查找并返回target对象上的name属性，找不到返回undefined<br/>
4、Reflect.set(target,name,value,receiver)//设置target对象上的name属性为value<br/>
5、Reflect.defineProperty(target,name,desc)//给对象定义属性<br/>
6、Reflect.deleteProperty(target,name)//删除target对象上的name属性<br/>
7、Reflect.has(target,name)//查找name属性是否属于target对象<br/>
8、Reflect.ownKeys(target)//返回对象所有属性<br/>
9、Reflect.isExtensible(target)//判断当前对象是否可扩展<br/>
10、Reflect.preventExtensions(target)/将对象变为不可扩展<br/>
11、Reflect.getOwnPropertyDescriptor(target,name)//得到指定属性的描述对象<br/>
12、Reflect.getPrototypeOf(target)//读取target对象上的__proto__属性<br/>
13、Reflect.setPrototypeOf(target, prototype)//设置target对象上的__proto__属性</p>
<h2 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 34px; border-bottom: 1px solid #dbdbdb; color: #333;">Promise对象</h2>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;">    Promise是异步编程的一种解决方案，相比回调和事件更合理和强大。它像一个容器，里面保存着未来才会结束的事件（通常是异步操作）的结果。
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">特点：</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">1、对象状态不受外界影响。有以下3种状态：pending(进行中)、fulfilled(已成功)、 rejected(已失败)。只受异步操作结果影响。<br/>
2、状态改变后就不会再变，任何时候都可以得到这个结果。（事件错过后再监听就无效，但是Promise对象状态变更后，再对它设置回调，也会得到结果）。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">缺点：</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">1、一旦新建它会立即执行，中途不能取消。<br/>
2、如果不设置回调函数，Promise内部抛出的错误，不会反应到外部。<br/>
3、当处于pending状态时，无法得知目前进展到哪一阶段。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">基本用法：</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">Promise对象是一个构造函数，可以使用new生成一个Promise实例。<br/>
Promise在新建后立即执行，then方法指定的回调函数，将在当前脚本所有同步任务执行完之后才会执行。<br/>
当一个异步操作(p2)的结果返回是另一个异步操作(p1)时，p1的状态决定了p2的状态。<br/>
调用resolve或reject并不会终结Promise参数函数的执行。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">Promise.prototype.then()</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">then方法返回的是一个新的Promise实例(不是原来是Promise实例)。因此可以使用链式写法。即在then方法后再跟另一个then方法。<br/>
第一个参数是resolved状态的回调函数，第二个参数(可选)是rejected状态的回调函数。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">Promise.prototype.catch()</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">捕获前面异步操作、then方法、catch方法抛出的错误。异步操作的reject方法等同于抛出错误(也会被catch捕获)，如果已经状态已经变成resolved，再抛出错误是无效。(建议使用catch方法，而不使用then方法的第二个参数)</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">Promise.all()</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">将多个Promise实例，包装成一个新的Promise实例。var p = Promise.all([p1,p2,p3]);<br/>
p的状态由p1,p2,p3决定：<br/>
1)、只有p1,p2,p3的状态都变成fulfilled,p的状态才会变成fulfilled。<br/>
2)、只要p1,p2,p3之中有一个被rejected,p的状态就会变成rejected，此时第一个reject的实例的返回值，会传递给p的回调函数。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">Promise.race()</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">将多个Promise实例，包装成一个新的Promise实例。var p = Promise.race([p1,p2,p3]);<br/>
p的状态由p1,p2,p3决定：<br/>
只要p1,p2,p3之中有一个实例率先改变状态，p的状态就跟着改变。那个率先改变的Promise实例的返回值，就传递给p的回调函数。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">Promise.resolve()</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">将现有对象转为Promise对象。<br/>
resolve方法的参数分为四种情况：<br/>
1)、参数是一个Promise实例。直接返回这个实例<br/>
2)、参数是一个具有then方法的对象。将这对象转换为Promise对象，然后立即执行then方法，然后状态改为resolved。<br/>
3)、参数不具有then方法或者根本不是对象。返回一个新的Promise对象，状态为resolved，并将参数传给回调函数。<br/>
4)、不带有任何参数。直接返回一个resolved状态的Promise对象。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">Promise.reject()</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">返回一个新的Promise实例，该实例状态为rejected。参数会传给回调函数。<br/>
附加方法<br/>
done()：总是处于回调链的尾端，保证抛出任何可能出现的错误。<br/>
finally()：不管异步操作状态是什么都保证执行。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">Promise.try()</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">当不知道或者不想区分函数f是同步函数还是异步操作，但是想用Promise来处理它，用then和catch同一处理。<br/>
try {<br/>
database.users.get({id: userId})<br/>
.then(...)<br/>
.catch(...)<br/>
} catch (e) {<br/>
// ...<br/>
}上面这样的写法就很笨拙上面这样的写法就很笨拙Promise 是异步编程的一种解决方案，比传统的解决方案——回调函数和 事件——更合理和更强大</p>
<h2 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 34px; border-bottom: 1px solid #dbdbdb; color: #333;">Iterator 和 for...of 循环</h2>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">遍历器(Iterator)是一种接口，为各种不同的数 据结构提供统一的访问机制。任何数据结构只要部署Iterator接口，就可 以完成遍历操作(即依次处理该数据结构的所有成员)。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">Iterator 的作用有三个:<br/>
一是为各种数据结构，提供一个统一的、简便的 访问接口;<br/>
二是使得数据结构的成员能够按某种次序排列;<br/>
三是ES6创 造了一种新的遍历命令 for...of 循环，Iterator接口主要<br/>
供 for...of 消费。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">Iterator 的遍历过程是这样的。<br/>
(1)创建一个指针对象，指向当前数据结构的起始位置。也就是说，遍 历器对象本质上，就是一个指针对象。<br/>
(2)第一次调用指针对象的 next 方法，可以将指针指向数据结构的 第一个成员。<br/>
(3)第二次调用指针对象的 next 方法，指针就指向数据结构的第二 个成员。<br/>
(4)不断调用指针对象的 next 方法，直到它指向数据结构的结束位 置。<br/>
每一次调用 next 方法，都会返回数据结构的当前成员的信息。具体来 说，就是返回一个包含 value 和 done 两个属性的对象。其<br/>
中， value 属性是当前成员的值， done 属性是一个布尔值，表示遍 历是否结束。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> it = makeIterator([<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'a'</span>, <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'b'</span>]);
it.next() <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// { value: "a", done: false }</span>
it.next() <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// { value: "b", done: false }</span>
it.next() <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// { value: undefined, done: true }</span>
<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">makeIterator</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">array</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> nextIndex = <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">0</span>;
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> {
    <span style="color: #9cdcfe; line-height: 160%; box-sizing: content-box;">next</span>: <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
      <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> nextIndex &lt; array.length ?
        {<span style="color: #9cdcfe; line-height: 160%; box-sizing: content-box;">value</span>: array[nextIndex++], <span style="color: #9cdcfe; line-height: 160%; box-sizing: content-box;">done</span>: <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">false</span>} :
        {<span style="color: #9cdcfe; line-height: 160%; box-sizing: content-box;">value</span>: <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">undefined</span>, <span style="color: #9cdcfe; line-height: 160%; box-sizing: content-box;">done</span>: <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">true</span>};
    }
}; }
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">如果使用 TypeScript 的写法，遍历器接口(Iterable)、指针对象 (Iterator)和 next 方法返回值的规格可以描述如下。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">interface</span> Iterable {
  [Symbol.iterator]() : Iterator,
}
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">interface</span> Iterator {
  next(value?: <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">any</span>) : IterationResult,
}
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">interface</span> IterationResult {
  value: <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">any</span>,
  done: <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">boolean</span>,
}
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">当使用 for...of 循环遍历某种 数据结构时，该循环会自动去寻找 Iterator 接口。<br/>
一种数据结构只要部署了 Iterator 接口，我们就称这种数据结构是”可遍 历的“(iterable)。<br/>
ES6 规定，默认的 Iterator 接口部署在数据结构的 Symbol.iterator 属 性，或者说，一个数据结构只要具有 Symbol.iterator 属性，就可以 认为是“可遍历的”(iterable)</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">原生具备 Iterator 接口的数据结构如下。<br/>
<em style="line-height: 160%; box-sizing: content-box; font-style: italic;"><strong style="line-height: 160%; box-sizing: content-box; font-weight: 700;">Array<br/>
Map<br/>
Set<br/>
String<br/>
TypedArray<br/>
函数的 arguments 对象 NodeList 对象</strong></em></p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">对于类似数组的对象(存在数值键名和 length 属性)，部署 Iterator 接口，有一个简便方法，就是 Symbol.iterator 方法直接引用数组的 Iterator 接口。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">调用 Iterator 接口的场合</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">(1)解构赋值<br/>
对数组和 Set 结构进行解构赋值时，会默认调用 Symbol.iterator 方法。<br/>
(2)扩展运算符<br/>
扩展运算符(...)也会调用默认的 Iterator 接口。<br/>
只要某个数据结构部署了 Iterator 接口，就 可以对它使用扩展运算符，将其转为数组。<br/>
(3)yield*<br/>
yield* 后面跟的是一个可遍历的结构，它会调用该结构的遍历器接口。<br/>
(4)其他场合 由于数组的遍历会调用遍历器接口，所以任何接受数组作为参数的场<br/>
合，其实都调用了遍历器接口。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">遍历器对象的return()，throw()</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">遍历器对象除了具有 next 方法，还可以具有 return 方法<br/>
和 throw 方法。如果你自己写遍历器对象生成函数，那么 next 方法 是必须部署的， return 方法和 throw 方法是否部署是可选的。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">return 方法的使用场合是，如果 for...of 循环提前退出(通常是因 为出错，或者有 break 语句或 continue 语句)，就会调用 return 方法。<br/>
throw 方法主要是配合 Generator 函数使用。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">for...of循环</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">JavaScript 原有的 for...in 循环，只能获得对象的键名，不能直接获 取键值。ES6 提供 for...of 循环，允许遍历获得键值。<br/>
for...of 循环调用遍历器接口，数组的遍历器接口只返回具有数字索 引的属性。这一点跟 for...in 循环也不一样。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">for...of 循环还有一个特点，就是会正确识别32位 UTF-16 字符。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">与其他遍历语法的比较</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">原始for循环：对于数组效率高，但写法比较麻烦。<br/>
forEach：对于数组效率高，写法方便，但是不允许中途退出。<br/>
for..of：对于数组效率高，写法方便，允许中途退出。<br/>
for...in：循环可以遍历数组的键名。<br/>
缺点：<br/>
1、数组的键名是数字，但是 for...in 循环是以字符串作为键 名“0”、“1”、“2”等等。<br/>
2、for...in 循环不仅遍历数字键名，还会遍历手动添加的其他键， 甚至包括原型链上的键。<br/>
3、某些情况下， for...in 循环会以任意顺序遍历键名。<br/>
总之，循环主要是为遍历对象而设计的，不适用于遍历数组。</p>
<h2 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 34px; border-bottom: 1px solid #dbdbdb; color: #333;">Generator 函数的语法</h2>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">Generator 函数是 ES6 提供的一种异步编程解决方案，可以把它理解成是一个状态机，封装了多个内部状态。<br/>
执行 Generator 函数会返回一个遍历器对象，返回的遍历器对象，可以依次遍历 Generator 函数内部的每一个状态。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;"><strong style="line-height: 160%; box-sizing: content-box; font-weight: 700;">特征：</strong><br/>
1、function 关键字与函数名之间有一个星号。<br/>
2、函数体内部使用 yield 表达式，定义不同的内部状态( yield 在英语里的意思就 是“产出”)。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">helloWorldGenerator</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'hello'</span>;
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'world'</span>;
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'ending'</span>;
}
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> hw = helloWorldGenerator();
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">上面代码定义了一个 Generator 函数 helloWorldGenerator ，它内部有 两个 yield 表达式( hello 和 world )，即该函数有三个状态: hello，world 和 return 语句(结束执行)。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">调用 Generator 函数后，该函数并不执行，而是返回一个遍历器对象(Iterator Object)，必须调用遍历器对象的 next 方法，使得指针移向下一个状态。也就是说，每次调用 next 方法，内部指针就从函数头部或上一次 停下来的地方开始执行，直到遇到下一个 yield 表达式(或 return 语句)为止。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;"><strong style="line-height: 160%; box-sizing: content-box; font-weight: 700;">遍历器对象的 next 方法的运行逻辑如下：</strong><br/>
(1)遇到 yield 表达式，就暂停执行后面的操作，并将紧跟<br/>
在 yield 后面的那个表达式的值，作为返回的对象的 value 属性值。<br/>
(2)下一次调用 next 方法时，再继续往下执行，直到遇到下一<br/>
个 yield 表达式。<br/>
(3)如果没有再遇到新的 yield 表达式，就一直运行到函数结束，直 到 return 语句为止，并将 return 语句后面的表达式的值，作为返回 的对象的 value 属性值。<br/>
(4)如果该函数没有 return 语句，则返回的对象的 value 属性值 为 undefined 。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">需要注意的是：<br/>
1、yield 表达式后面的表达式，只有当调用 next 方法、内部指针指向该语句时才会执行<br/>
2、yield 表达式只能用在 Generator 函数里面，用在其他 地方都会报错<br/>
3、yield 表达式如果用在另一个表达式之中，必须放在圆括号里 面。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">demo</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'Hello'</span> + <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span>); <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// SyntaxError</span>
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'Hello'</span> + <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">123</span>); <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// SyntaxError</span>
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'Hello'</span> + (<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span>)); <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// OK</span>
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'Hello'</span> + (<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">123</span>)); <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// OK</span>
}
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">4、yield 表达式用作函数参数或放在赋值表达式的右边，可以不加括号。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">demo</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  foo(<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'a'</span>, <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'b'</span>); <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// OK</span>
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> input = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span>; <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// OK</span>
}
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">与 Iterator 接口的关系</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">上一章说过，任意一个对象的 Symbol.iterator 方法，等于该对象的<br/>
遍历器生成函数，调用该函数会返回该对象的一个遍历器对象。<br/>
由于 Generator 函数就是遍历器生成函数，因此可以把 Generator 赋值给对象的 Symbol.iterator 属性，从而使得该对象具有 Iterator 接口。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">Generator 函数执行后，返回一个遍历器对象。该对象本身也具 有 Symbol.iterator 属性，执行后返回自身。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">gen</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>)</span>{
  <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// some code</span>
}
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> g = gen();
g[Symbol.iterator]() === g
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// true</span>
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">next 方法的参数</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">yield 表达式本身没有返回值，或者说总是返回 undefined 。 next 方法可以带一个参数，该参数就会被当作上一个 yield 表达式的返回值。<br/>
<em style="line-height: 160%; box-sizing: content-box; font-style: italic;">注意，由于 next 方法的参数表示上一个 yield 表达式的返回值，所 以在第一次使用 next 方法时，传递参数是无效的。V8 引擎直接忽略第 一次使用 next 方法时的参数，只有从第二次使用 next 方法开始，参 数才是有效的。</em></p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">for...of 循环</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">for...of 循环可以自动遍历 Generator 函数时生成的 Iterator 对象，且此时不再需要调用 next 方法。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;"><em style="line-height: 160%; box-sizing: content-box; font-style: italic;">需要注意，一旦 next 方法的返回对象的 done 属性<br/>
为 true ， for...of 循环就会中止，且不包含该返回对象，所以上面 代码的 return 语句返回的 6 ，不包括在 for...of 循环之中。</em></p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">Generator.prototype.throw()</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">Generator 函数返回的遍历器对象，都有一个 throw 方法，可以在函数 体外抛出错误，然后在 Generator 函数体内捕获。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;"><em style="line-height: 160%; box-sizing: content-box; font-style: italic;">注意，不要混淆遍历器对象的 throw 方法和全局的 throw 命令。上面 代码的错误，是用遍历器对象的 throw 方法抛出的，而不是用 throw 命令抛出的。后者只能被函数体外的 catch 语句捕获。</em></p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">throw 方法被捕获以后，会附带执行下一条 yield 表达式。也就是 说，会附带执行一次 next 方法。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> gen = <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">gen</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>)</span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">try</span> {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'a'</span>);
  } <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">catch</span> (e) {
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ...</span>
  }
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'b'</span>);
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'c'</span>);
}
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> g = gen();
g.next() <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// a</span>
g.throw() <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// b</span>
g.next() <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// c</span>
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">一旦 Generator 执行过程中抛出错误，且没有被内部捕获，就不会再执行 下去了。如果此后还调用 next 方法，将返回一个 value 属性等于 undefined 、 done 属性等于 true 的对象，即 JavaScript 引擎认 为这个 Generator 已经运行结束了</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">Generator.prototype.return()</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">Generator 函数返回的遍历器对象，还有一个 return 方法，可以返回给定的值，并且终结遍历 Generator 函数。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">gen</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">1</span>;
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">2</span>;
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">3</span>;
}
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> g = gen();
g.next()
g.return(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'foo'</span>) <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// { value: "foo", done: true }</span>
g.next()        <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// { value: undefined, done: true }</span>
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">如果 return 方法调用时，不提供参数，则返回值的 value 属性 为 undefined 。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">如果 Generator 函数内部有 try...finally 代码块，那么 return 方法 会推迟到 finally 代码块执行完再执行。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">numbers</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">1</span>;
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">try</span> {
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">2</span>;
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">3</span>;
  } <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">finally</span> {
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">4</span>;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">5</span>; }
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">6</span>; }
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> g = numbers();
g.next() <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// { value: 1, done: false }</span>
g.next() <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// { value: 2, done: false }</span>
g.return(<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">7</span>) <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// { value: 4, done: false }</span>
g.next() <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// { value: 5, done: false }</span>
g.next() <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// { value: 7, done: true }</span>
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">yield* 表达式</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">如果在 Generator 函数内部，调用另一个 Generator 函数，默认情况下是没有效果的，这时就需要用到 yield* 表达式，用来在一个 Generator 函数里面执行 另一个Generator 函数。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">bar</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'x'</span>;
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span>* foo();
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'y'</span>;
}
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 等同于 function* bar() {</span>
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'x'</span>;
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'a'</span>;
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'b'</span>;
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'y'</span>;
}
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 等同于 function* bar() {</span>
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'x'</span>;
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">for</span> (<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> v <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">of</span> foo()) {
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> v; }
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'y'</span>; }
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">for</span> (<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> v <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">of</span> bar()){
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(v);
}
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// "x"</span>
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// "a"</span>
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// "b"</span>
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// "y"</span>
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;"><em style="line-height: 160%; box-sizing: content-box; font-style: italic;">yield</em> 后面的Generator函数(没有 return 语句 时)，不过是 for...of 的一种简写形式，完全可以用后者替代前者。 反之，在有 return 语句时，则需要用 var value = yield* iterator 的形式获取 return 语句的值。*</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">任何数据结构只要有 Iterator 接口，就可以被 yield* 遍历。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">作为对象属性的Generator函数</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">如果一个对象的属性是 Generator 函数，可以简写成下面的形式。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> obj = {
  * myGeneratorMethod() {
··· }
};

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//等同于</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> obj = {
  <span style="color: #9cdcfe; line-height: 160%; box-sizing: content-box;">myGeneratorMethod</span>: <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ···</span>
} };
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">Generator 函数的 this</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">Generator 函数总是返回一个遍历器，ES6 规定这个遍历器是 Generator函数的实例，也继承了 Generator 函数的 prototype 对象上的方法。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">g</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{}
g.prototype.hello = <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'hi!'</span>;
};
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> obj = g();
obj <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">instanceof</span> g <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// true</span>
obj.hello() <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 'hi!'</span>
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">上面代码表明，Generator 函数 g 返回的遍历器 obj ，是 g 的实例， 而且继承了 g.prototype 。但是，如果把 g 当作普通的构造函数，并不会生效，因为 g 返回的总是遍历器对象，而不是 this 对象。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">g</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>.a = <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">11</span>;
}
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> obj = g();
obj.a <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// undefined</span>
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">上面代码中，Generator函数 g 在 this 对象上面添加了一个属性 a ， 但是 obj 对象拿不到这个属性。<br/>
<em style="line-height: 160%; box-sizing: content-box; font-style: italic;">Generator函数也不能跟 new 命令一起用，会报错。</em></p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">Generator 与状态机</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">Generator 是实现状态机的最佳结构。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> ticking = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">true</span>;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> clock = <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">if</span> (ticking)
    <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'Tick!'</span>);
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">else</span>
    <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'Tock!'</span>);
  ticking = !ticking;
}

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//少了用来保存状态的 外部变量 ticking。 更简洁，更安全</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> clock = <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">while</span> (<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">true</span>) {
    <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'Tick!'</span>);
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span>;
    <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'Tock!'</span>);
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span>;
} };
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">Generator与协程</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">协程(coroutine)是一种程序运行的方式，可以理解成“协作的线 程”或“协作的函数”。协程既可以用单线程实现，也可以用多线程实现。 前者是一种特殊的子例程，后者是一种特殊的线程。</p>
<h5 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 16px; color: #333;">(1)协程与子例程的差异</h5>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">传统的“子例程”(subroutine)采用堆栈式“后进先出”的执行方式，只有 当调用的子函数完全执行完毕，才会结束执行父函数。协程与其不同， 多个线程(单线程情况下，即多个函数)可以并行执行，但是只有一个 线程(或函数)处于正在运行的状态，其他线程(或函数)都处于暂停 态(suspended)，线程(或函数)之间可以交换执行权。也就是说，一 个线程(或函数)执行到一半，可以暂停执行，将执行权交给另一个线 程(或函数)，等到稍后收回执行权的时候，再恢复执行。这种可以并 行执行、交换执行权的线程(或函数)，就称为协程。<br/>
从实现上看，在内存中，子例程只使用一个栈(stack)，而协程是同时 存在多个栈，但只有一个栈是在运行状态，也就是说，协程是以多占用 内存为代价，实现多任务的并行。</p>
<h5 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 16px; color: #333;">(2)协程与普通线程的差异</h5>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">协程与普通的线程很相似，都有自己的执行上下文、可以分享全局变量。<br/>
不同：<br/>
1、同一时间可以有多个线程处于运行状态，但是运行的协程<br/>
只能有一个，其他协程都处于暂停状态。<br/>
2、普通的线程是抢先式的，到底哪个线程优先得到资源，必须由运行环境决定，但是协程是合作式的，执行权由协程自己分配。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">由于 JavaScript 是单线程语言，只能保持一个调用栈。引入协程以后， 每个任务可以保持自己的调用栈。这样做的最大好处，就是抛出错误的 时候，可以找到原始的调用栈。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">Generator 函数是 ES6 对协程的实现，但属于不完全实现。Generator 函 数被称为“半协程”(semi-coroutine)，意思是只有 Generator 函数的调用 者，才能将程序的执行权还给 Generator 函数。如果是完全执行的协程， 任何函数都可以让暂停的协程继续执行。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">应用</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">Generator 可以暂停函数执行，返回任意表达式的值。这种特点使得 Generator 有多种应用场景。</p>
<h5 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 16px; color: #333;">(1)异步操作的同步化表达</h5>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">loadUI</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  showLoadingScreen();
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> loadUIDataAsynchronously();
  hideLoadingScreen();
}
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> loader = loadUI(); <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 加载UI loader.next()</span>
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 卸载UI</span>
loader.next()
</code></pre>
<h5 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 16px; color: #333;">(2)控制流管理</h5>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">有一个多步操作非常耗时，采用回调函数，可能会写成下面这样</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//普通实现</span>
step1(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">value1</span>) </span>{
  step2(value1, <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">value2</span>) </span>{
    step3(value2, <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">value3</span>) </span>{
      step4(value3, <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">value4</span>) </span>{
        <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// Do something with value4</span>
}); });
}); });

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//Promise 实现</span>
<span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Promise</span>.resolve(step1)
  .then(step2)
  .then(step3)
  .then(step4)
  .then(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">value4</span>) </span>{
    <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// Do something with value4</span>
  }, <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">error</span>) </span>{
    <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// Handle any error from step1 through step4</span>
}) .done();

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//Generator 实现</span>
<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">longRunningTask</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">value1</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">try</span> {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> value2 = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> step1(value1);
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> value3 = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> step2(value2);
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> value4 = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> step3(value3);
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> value5 = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> step4(value4);
    <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// Do something with value4</span>
  } <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">catch</span> (e) {
    <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// Handle any error from step1 through step4</span>
} }
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;"><em style="line-height: 160%; box-sizing: content-box; font-style: italic;">上面这种做法，只适合同步操作，即所有的 task 都必须是同步 的，不能有异步操作。因为这里的代码一得到返回值，就继续往下执 行，没有判断异步操作何时完成。</em></p>
<h5 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 16px; color: #333;">(3)部署 Iterator 接口</h5>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">iterEntries</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">obj</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> keys = <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Object</span>.keys(obj);
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">for</span> (<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> i=<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">0</span>; i &lt; keys.length; i++) {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> key = keys[i];
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> [key, obj[key]];
  }
}
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> myObj = { <span style="color: #9cdcfe; line-height: 160%; box-sizing: content-box;">foo</span>: <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">3</span>, <span style="color: #9cdcfe; line-height: 160%; box-sizing: content-box;">bar</span>: <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">7</span> };
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">for</span> (<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> [key, value] <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">of</span> iterEntries(myObj)) {
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(key, value);
}
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// foo 3</span>
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// bar 7</span>
</code></pre>
<h5 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 16px; color: #333;">(4)作为数据结构</h5>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">Generator 可以看作是数据结构，更确切地说，可以看作是一个数组结 构，因为 Generator 函数可以返回一系列的值，这意味着它可以对任意表达式，提供类似数组的接口。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> *<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">doStuff</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> fs.readFile.bind(<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">null</span>, <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'hello.txt'</span>);
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> fs.readFile.bind(<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">null</span>, <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'world.txt'</span>);
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> fs.readFile.bind(<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">null</span>, <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'and-such.txt'</span>);
}
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">上面代码就是依次返回三个函数，但是由于使用了 Generator 函数，导致 可以像处理数组那样，处理这三个返回的函数。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">for</span> (task <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">of</span> doStuff()) {
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// task是一个函数，可以像回调函数那样使用它</span>
}
</code></pre>
<h2 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 34px; border-bottom: 1px solid #dbdbdb; color: #333;">Generator 函数的异步应用</h2>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">ES6 诞生以前，异步编程的方法，大概有下面四种。<br/>
1.回调函数<br/>
2.事件监听<br/>
3.发布/订阅<br/>
4.Promise 对象</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">所谓”异步”，简单说就是一个任务不是连续完成的，可以理解成该任务 被人为分成两段，先执行第一段，然后转而执行其他任务，等做好了准 备，再回过头执行第二段。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">回调函数</h4>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;">fs.readFile(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'/etc/passwd'</span>, <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'utf-8'</span>, <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">err, data</span>)
</span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">if</span> (err) <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">throw</span> err;
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(data);
});
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">一个有趣的问题是，为什么Node约定，回调函数的第一个参数，必须是错误对象err(如果没有错误，该参数就是null)?原因是执行分成两段，第一段执行完以后，任务所在的上下文环境就已经结束了。在这以后抛出的错误，原来的上下文环境已经无法捕捉，只能当作参数，传入第二段。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">Promise</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">回调函数本身并没有问题，它的问题出现在多个回调函数嵌套。假定读 取 A 文件之后，再读取 B 文件，代码如下。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;">fs.readFile(fileA, <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'utf-8'</span>, <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">err, data</span>) </span>{
  fs.readFile(fileB, <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'utf-8'</span>, <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">err, data</span>) </span>{
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ...</span>
}); });
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">如果依次读取两个以上的文件，就会出现多重嵌套。代码因为多个 异步操作形成了强耦合，只要有一个操作需要修改，它的上层回调函数和下层回调函数，可能都要跟着修改。这种情况就称为”回调函数地 狱”(callback hell)。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">Promise 对象就是为了解决这个问题而提出的。它不是新的语法功能，而 是一种新的写法，允许将回调函数的嵌套，改成链式调用。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> readFile = <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">require</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'fs-readfile-promise'</span>);
readFile(fileA)
.then(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">data</span>) </span>{
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(data.toString());
})
.then(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> readFile(fileB);
})
.then(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">data</span>) </span>{
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(data.toString());
})
.catch(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">err</span>) </span>{
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(err);
});
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;"><em style="line-height: 160%; box-sizing: content-box; font-style: italic;">Promise 的最大问题是代码冗余，原来的任务被 Promise 包装了一下，不 管什么操作，一眼看去都是一堆 then ，原来的语义变得很不清楚。</em></p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">Generator 函数</h4>
<h5 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 16px; color: #333;">协程</h5>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">协程有点像函数，又有点像线程。它的运行流程大致如下。<br/>
第一步，协程A开始执行。<br/>
第二步，协程A执行到一半，进入暂停，执行权转移到协程B。<br/>
第三步，(一段时间后)协程B交还执行权。<br/>
第四步，协程A恢复执行。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">Generator 函数是协程在 ES6 的实现，最大特点就是可以交出函数的执行权(即暂停执行)。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">Thunk 函数</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">Thunk 函数是自动执行 Generator 函数的一种方法</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">编译器的“传名调用”实现，往往是将参数放到一个临时函数之中，再将这个临时函数传入函数体。这个临时函数就叫做 Thunk 函数。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">f</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">m</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> m * <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">2</span>;
}
f(x + <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">5</span>); <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 等同于</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> thunk = <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> x + <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">5</span>;
};
<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">f</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">thunk</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> thunk() * <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">2</span>;
}
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">JavaScript 语言的 Thunk 函数</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">JavaScript 语言是传值调用，它的 Thunk 函数含义有所不同。在 JavaScript 语言中，Thunk 函数替换的不是表达式，而是多参数函数，将 其替换成一个只接受回调函数作为参数的单参数函数。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 正常版本的readFile(多参数版本)</span>
fs.readFile(fileName, callback);
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// Thunk版本的readFile(单参数版本)</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> Thunk = <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">fileName</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">callback</span>) </span>{
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> fs.readFile(fileName, callback);
  };
};
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> readFileThunk = Thunk(fileName);
readFileThunk(callback);
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">Thunkify 模块</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">安装:</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;">$ npm install thunkify
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">使用方式:</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> thunkify = <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">require</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'thunkify'</span>);
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> fs = <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">require</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'fs'</span>);
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> read = thunkify(fs.readFile);
read(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'package.json'</span>)(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">err, str</span>)</span>{
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ...</span>
});
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">源码:</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">thunkify</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">fn</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> args = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Array</span>(<span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">arguments</span>.length);
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> ctx = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>;
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">for</span> (<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> i = <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">0</span>; i &lt; args.length; ++i) {
      args[i] = <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">arguments</span>[i];
    }
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">done</span>) </span>{
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> called;
      args.push(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
        <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">if</span> (called) <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span>;
        called = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">true</span>;
        done.apply(<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">null</span>, <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">arguments</span>);
});
      <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">try</span> {
        fn.apply(ctx, args);
      } <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">catch</span> (err) {
        done(err);
} }
} };
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">它的源码主要多了一个检查机制，变量 called 确保回调函数只运行一 次。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">Generator 函数的流程管理</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">ES6 有了 Generator 函数，Thunk 函数现在可以用于 Generator 函数的自动流程管理。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">gen</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
&nbsp;&nbsp; <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ...</span>
  }
  
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> g = gen();
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> res = g.next();

<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">while</span>(!res.done){
&nbsp;&nbsp; <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(res.value);
&nbsp;&nbsp; res = g.next();
  }
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">上面代码中，Generator 函数 gen 会自动执行完所有步骤。<br/>
但是，这不适合异步操作。如果必须保证前一步执行完，才能执行后一 步，上面的自动执行就不可行。这时，Thunk 函数就能派上用处。以读 取文件为例。下面的 Generator 函数封装了两个异步操作。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> fs = <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">require</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'fs'</span>);
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> thunkify = <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">require</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'thunkify'</span>);
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> readFileThunk = thunkify(fs.readFile);
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> gen = <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>)</span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> r1 = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> readFileThunk(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'/etc/fstab'</span>);
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(r1.toString());
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> r2 = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> readFileThunk(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'/etc/shells'</span>);
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(r2.toString());
};
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">手动执行上面这个 Generator 函数:</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> g = gen();
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> r1 = g.next();
r1.value(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">err, data</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">if</span> (err) <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">throw</span> err;
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> r2 = g.next(data);
  r2.value(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">err, data</span>) </span>{
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">if</span> (err) <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">throw</span> err;
    g.next(data);
  });
});
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">Thunk 函数的自动流程管理:</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">run</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">fn</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> gen = fn();
  <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">next</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">err, data</span>) </span>{
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> result = gen.next(data);
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">if</span> (result.done) <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span>;
    result.value(next);
}
next(); }
<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">g</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ...</span>
} run(g);
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">有了这个执行器，执行 Generator 函数方便多了。不管内部有多少个异步 操作，直接把 Generator 函数传入 run 函数即可。当然，前提是每一个 异步操作，都要是 Thunk 函数，也就是说，跟在 yield 命令后面的必 须是 Thunk 函数。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">co 模块</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">co 模块是著名程序员 TJ Holowaychuk 于2013年6月发布的一个小工具， 用于 Generator 函数的自动执行。<br/>
co 模块可以让你不用编写 Generator 函数的执行器。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> co = <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">require</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'co'</span>);
co(gen);
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">co 函数返回一个 Promise 对象，因此可以用 then 方法添加回调函数。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;">co(gen).then(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>)</span>{ <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'Generator 函数执行完成'</span>);
});
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">基于 Promise 对象的自动执行</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">还是沿用上面的例子。首先，把 fs 模块的 readFile 方法包装成一个 Promise 对象。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> fs = <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">require</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'fs'</span>);
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> readFile = <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">fileName</span>)</span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Promise</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">resolve, reject</span>)</span>{
    fs.readFile(fileName, <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">error, data</span>)</span>{
      <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">if</span> (error) <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> reject(error);
      resolve(data);
}); });
};
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> gen = <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>)</span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> f1 = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> readFile(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'/etc/fstab'</span>);
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> f2 = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> readFile(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'/etc/shells'</span>);
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(f1.toString());
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(f2.toString());
};
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">然后，手动执行上面的 Generator 函数:</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> g = gen();
g.next().value.then(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">data</span>)</span>{
  g.next(data).value.then(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">data</span>)</span>{
    g.next(data);
  });
});
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">自动执行器:</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">run</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">gen</span>)</span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> g = gen();
  <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">next</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">data</span>)</span>{
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> result = g.next(data);
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">if</span> (result.done) <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> result.value;
    result.value.then(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">data</span>)</span>{
      next(data);
    });
}
next(); }
run(gen);
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">co 模块</h4>
<h5 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 16px; color: #333;">原理</h5>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">co 模块其实就是将两种自动执行器(Thunk 函数和 Promise 对象)，包 装成一个模块。使用 co 的前提条件是，Generator 函数的 yield 命令后 面，只能是 Thunk 函数或 Promise 对象。如果数组或对象的成员，全部 都是 Promise 对象，也可以使用 co</p>
<h5 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 16px; color: #333;">源码</h5>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">首先，co 函数接受 Generator 函数作为参数，返回一个 Promise 对象。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">co</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">gen</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> ctx = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>;
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Promise</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">resolve, reject</span>) </span>{
}); }
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">在返回的 Promise 对象里面，co 先检查参数 gen 是否为 Generator 函 数。如果是，就执行该函数，得到一个内部指针对象;如果不是就返 回，并将 Promise 对象的状态改为 resolved 。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">co</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">gen</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> ctx = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>;
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Promise</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">resolve, reject</span>) </span>{
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">if</span> (<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">typeof</span> gen === <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'function'</span>) gen = gen.call(ctx);
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">if</span> (!gen || <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">typeof</span> gen.next !== <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'function'</span>) <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span>
resolve(gen);
  });
}
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">接着，co 将 Generator 函数的内部指针对象的 next 方法，包装 成 onFulfilled 函数。这主要是为了能够捕捉抛出的错误。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">co</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">gen</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> ctx = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>;
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Promise</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">resolve, reject</span>) </span>{
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">if</span> (<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">typeof</span> gen === <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'function'</span>) gen = gen.call(ctx);
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">if</span> (!gen || <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">typeof</span> gen.next !== <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'function'</span>) <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span>
resolve(gen);
    onFulfilled();
    <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">onFulfilled</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">res</span>) </span>{
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> ret; <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">try</span> {
        ret = gen.next(res);
      } <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">catch</span> (e) {
        <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> reject(e);
      }
next(ret); }
}); }
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">最后，就是关键的 next 函数，它会反复调用自身。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;">function next(ret) {
  if (ret.done){
    return resolve(ret.value);
  }
  var value = toPromise.call(ctx, ret.value);
  if (value &amp;&amp; isPromise(value)){
    return value.then(onFulfilled, onRejected);
  }
  return onRejected(
    new TypeError(
      'You may only yield a function, promise,
generator, array, or object, '
      + 'but the following object was passed: "'
      + String(ret.value)
      + '"'
    )
  );
}
</code></pre>
<h5 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 16px; color: #333;">处理并发的异步操作</h5>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">co 支持并发的异步操作，即允许某些操作同时进行，等到它们全部完成，才进行下一步。<br/>
这时，要把并发的操作都放在数组或对象里面，跟在 yield 语句后面。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 数组的写法1</span>
co(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> res = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> [
    <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Promise</span>.resolve(<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">1</span>),
    <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Promise</span>.resolve(<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">2</span>)
  ];
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(res);
}).catch(onerror);

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 数组的写法2</span>
co(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> values = [n1, n2, n3];
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> values.map(somethingAsync);
});
<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">somethingAsync</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">x</span>) </span>{
  <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// do something async</span>
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> y
}

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 对象的写法</span>
co(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> res = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> {
    <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">1</span>: <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Promise</span>.resolve(<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">1</span>),
    <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">2</span>: <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Promise</span>.resolve(<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">2</span>),
  };
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(res);
}).catch(onerror);

</code></pre>
<h2 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 34px; border-bottom: 1px solid #dbdbdb; color: #333;">async 函数</h2>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">ES2017 标准引入了 async 函数，使得异步操作变得更加方便。 async 函数是什么?一句话，它就是 Generator 函数的语法糖。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">前文有一个 Generator 函数，依次读取两个文件。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> fs = <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">require</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'fs'</span>);
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> readFile = <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">fileName</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Promise</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">resolve, reject</span>) </span>{
    fs.readFile(fileName, <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">error, data</span>) </span>{
      <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">if</span> (error) <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> reject(error);
      resolve(data);
    });
}); };
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> gen = <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> f1 = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> readFile(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'/etc/fstab'</span>);
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> f2 = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">yield</span> readFile(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'/etc/shells'</span>);
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(f1.toString());
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(f2.toString());
};
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">写成 async 函数，就是下面这样。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> asyncReadFile = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">async</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> f1 = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">await</span> readFile(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'/etc/fstab'</span>);
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> f2 = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">await</span> readFile(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'/etc/shells'</span>);
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(f1.toString());
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(f2.toString());
};
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">async 函数就是将 Generator 函数的星号( * )替 换成 async ，将 yield 替换成 await ，仅此而已。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">async 函数对 Generator 函数的改进。<br/>
(1)内置执行器。<br/>
async 函数的执行，与普通函 数一模一样</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;">asyncReadFile();
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">(2)更好的语义。<br/>
(3)更广的适用性。<br/>
async 函数的 await 命令后面，可以是Promise 对象和原始类型的 值(数值、字符串和布尔值，但这时等同于同步操作)。<br/>
(4)返回值是 Promise。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">基本用法</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">async 函数返回一个 Promise 对象，可以使用 then 方法添加回调函 数。当函数执行的时候，一旦遇到 await 就会先返回，等到异步操作 完成，再接着执行函数体内后面的语句。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">timeout</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">ms</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Promise</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">resolve</span>) =&gt;</span> {
    setTimeout(resolve, ms);
  });
}
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">async</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">asyncPrint</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">value, ms</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">await</span> timeout(ms);
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(value);
}
asyncPrint(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'hello world'</span>, <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">50</span>);
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">上面代码指定50毫秒以后，输出 hello world 。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">async 函数有多种使用形式。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 函数声明</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">async</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">foo</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{}
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 函数表达式</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> foo = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">async</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{};
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 对象的方法</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> obj = { <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">async</span> foo() {} };
obj.foo().then(...)
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// Class 的方法 class Storage {</span>
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">constructor</span>() {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>.cachePromise = caches.open(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'avatars'</span>);
}
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">async</span> getAvatar(name) {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> cache = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">await</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>.cachePromise;
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> cache.match(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">`/avatars/<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">${name}</span>.jpg`</span>);
} }
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> storage = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> Storage();
storage.getAvatar(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'jake'</span>).then(...);
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 箭头函数</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> foo = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">async</span> () =&gt; {};
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">语法</h4>
<h5 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 16px; color: #333;">返回 Promise 对象</h5>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">async 函数返回一个 Promise 对象。<br/>
async 函数内部 return 语句返回的值，会成为 then 方法回调函数 的参数。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">async</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">f</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'hello world'</span>;
}
f().then(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">v</span> =&gt;</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(v))
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// "hello world"</span>
</code></pre>
<h5 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 16px; color: #333;">Promise 对象的状态变化</h5>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">async 函数返回的 Promise 对象，必须等到内部所有 await 命令后面 的 Promise 对象执行完，才会发生状态改变，除非遇到 return 语句或 者抛出错误。</p>
<h5 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 16px; color: #333;">await 命令</h5>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">正常情况下， await 命令后面是一个 Promise 对象。如果不是，会被转<br/>
成一个立即 resolve 的 Promise 对象。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">await 命令后面的 Promise 对象如果变为 reject 状态， 则 reject 的参数会被 catch 方法的回调函数接收到。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">async</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">f</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">await</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Promise</span>.reject(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'出错了'</span>);
}
f()
.then(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">v</span> =&gt;</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(v)) .catch(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">e</span> =&gt;</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(e)) <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 出错了</span>
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">只要一个 await 语句后面的 Promise 变为 reject ，那么整 个 async 函数都会中断执行。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">错误处理</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">如果 await 后面的异步操作出错，那么等同于 async 函数返回的<br/>
Promise 对象被 reject 。<br/>
防止出错的方法，也是将其放在 try...catch 代码块之中。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">async</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">f</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">try</span> {
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">await</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Promise</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">resolve, reject</span>) </span>{ <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">throw</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Error</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'出错了'</span>);
    });
  } <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">catch</span>(e) {
  }
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">await</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'hello world'</span>);
}
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">使用注意点</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">第一点，前面已经说过， await 命令后面的 Promise 对象，运行结果 可能是 rejected ，所以最好把 await 命令放在 try...catch 代码 块中。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">第二点，多个 await 命令后面的异步操作，如果不存在继发关系，最 好让它们同时触发。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 写法一</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> [foo, bar] = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">await</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Promise</span>.all([getFoo(),
getBar()]);
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 写法二</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> fooPromise = getFoo();
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> barPromise = getBar();
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> foo = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">await</span> fooPromise;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> bar = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">await</span> barPromise;
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">第三点， await 命令只能用在 async 函数之中，如果用在普通函数， 就会报错。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">async 函数的实现原理</h4>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">async</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">fn</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">args</span>) </span>{
  <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ...</span>
}
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 等同于</span>
<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">fn</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">args</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> spawn(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>* (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ...</span>
}); }

<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">spawn</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">genF</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Promise</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">resolve, reject</span>) </span>{
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> gen = genF();
    <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">step</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">nextF</span>) </span>{
      <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> next;
      <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">try</span> {
        next = nextF();
      } <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">catch</span>(e) {
        <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> reject(e);
      }
      <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">if</span>(next.done) {
        <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> resolve(next.value);
      }
      <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Promise</span>.resolve(next.value).then(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">v</span>) </span>{
        step(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{ <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> gen.next(v); });
      }, <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">e</span>) </span>{
        step(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{ <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> gen.throw(e); });
      });
}
    step(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{ <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> gen.next(<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">undefined</span>); });
  });
}
</code></pre>
<h5 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 16px; color: #333;">实例:按顺序完成异步操作</h5>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">async</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">logInOrder</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">urls</span>) </span>{
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 并发读取远程URL</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> textPromises = urls.map(<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">async</span> url =&gt; {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> response = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">await</span> fetch(url);
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> response.text();
  });
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 按次序输出</span>
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">for</span> (<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> textPromise <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">of</span> textPromises) {
    <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">await</span> textPromise);
} }
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">上面代码中，虽然 map 方法的参数是 async 函数，但它是并发执行 的，因为只有 async 函数内部是继发执行，外部不受影响。</p>
<h2 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 34px; border-bottom: 1px solid #dbdbdb; color: #333;">Class 的基本语法</h2>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">ES6 的 class 可以看作只是一个语法糖，它的绝大部分功能， ES5 都可以做到，新的 class 写法只是让对象原型的写法更加清晰、更 像面向对象编程的语法而已。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//定义类</span>
<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Point</span> </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">constructor</span>(x, y) {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>.x = x;
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>.y = y;
}
  toString() {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'('</span> + <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>.x + <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">', '</span> + <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>.y + <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">')'</span>;
} }
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">定 义“类”的方法的时候，前面不需要加上 function 这个关键字，直接把函数定义放进去了就可以了。另外，方法之间不需要逗号分隔，加了会报错。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Point</span> </span>{
  <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ...</span>
}
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">typeof</span> Point <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// "function"</span>
Point === Point.prototype.constructor <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// true</span>
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">上面代码表明，类的数据类型就是函数，类本身就指向构造函数。<br/>
构造函数的 prototype 属性，在 ES6 的“类”上面继续存在。事实上， 类的所有方法都定义在类的 prototype 属性上面。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Point</span> </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">constructor</span>() {
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ...</span>
}
toString() {
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ...</span>
}
toValue() {
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ...</span>
} }
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 等同于</span>
Point.prototype = {
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">constructor</span>() {},
  toString() {},
  toValue() {},
};
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">在类的实例上面调用方法，其实就是调用原型上的方法。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;"><strong style="line-height: 160%; box-sizing: content-box; font-weight: 700;">类的内部所有定义的方法，都是不可枚举的(non-enumerable)。</strong></p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">类的属性名，可以采用表达式。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> methodName = <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'getArea'</span>;
<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Square</span> </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">constructor</span>(length) {
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ...</span>
}
  [methodName]() {
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ...</span>
} }
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">严格模式</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">类和模块的内部，默认就是严格模式，只要你的代码写在类或模块之中，就只有严格模式可用。考虑到未来所有的代码，其实都是运行在模块之中，所以 ES6 实际上把 整个语言升级到了严格模式。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">constructor 方法</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">constructor 方法是类的默认方法，通过 new 命令生成对象实例时， 自动调用该方法。一个类必须有 constructor 方法，如果没有显式定 义，一个空的 constructor 方法会被默认添加。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Point</span> </span>{
}
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 等同于 class Point {</span>
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">constructor</span>() {}
}
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">constructor 方法默认返回实例对象(即 this )，完全可以指定返回另外一个对象。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Foo</span> </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">constructor</span>() {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Object</span>.create(<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">null</span>);
  }
}
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> Foo() <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">instanceof</span> Foo
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// false</span>

</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">类的实例对象</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">实例的属性除非显式定义在其本身(即定义在 this 对象 上)，否则都是定义在原型上(即定义在 class 上)。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//定义类</span>
<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Point</span> </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">constructor</span>(x, y) {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>.x = x;
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>.y = y;
}
  toString() {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'('</span> + <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>.x + <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">', '</span> + <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>.y + <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">')'</span>;
} }
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> point = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> Point(<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">2</span>, <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">3</span>);
point.toString() <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// (2, 3)</span>
point.hasOwnProperty(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'x'</span>) <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// true</span>
point.hasOwnProperty(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'y'</span>) <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// true</span>
point.hasOwnProperty(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'toString'</span>) <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// false</span>
point.__proto__.hasOwnProperty(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'toString'</span>) <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// true</span>
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">与 ES5 一样，类的所有实例共享一个原型对象。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">Class 表达式</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">与函数一样，类也可以使用表达式的形式定义。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> MyClass = <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Me</span> </span>{
  getClassName() {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> Me.name;
  }
};

<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> inst = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> MyClass();
inst.getClassName() <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// Me</span>
Me.name <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ReferenceError: Me is not defined</span>
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">需要注意的是，这个类的名字是 MyClass 而不是 Me ， Me 只在 Class 的内部代码可用，指代当前类。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">不存在变量提升</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">类不存在变量提升(hoist)</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">私有方法</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">一种做法是在命名上加以区别。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Widget</span> </span>{
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 公有方法</span>
  foo (baz) {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>._bar(baz);
}
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 私有方法</span>
  _bar(baz) {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>.snaf = baz;
}
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ...</span>
}
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">但是，这种命名是不保险的，在类的外部，还是可以调用 到这个方法。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">另一种方法就是索性将私有方法移出模块，因为模块内部的所有方法都<br/>
是对外可见的。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Widget</span> </span>{
  foo (baz) {
    bar.call(<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>, baz);
  }
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ...</span>
}
<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">bar</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">baz</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>.snaf = baz;
}
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">上面代码中， foo 是公有方法，内部调用了 bar.call(this, baz) 。 这使得 bar 实际上成为了当前模块的私有方法。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">还有一种方法是利用 Symbol 值的唯一性，将私有方法的名字命名为一 个 Symbol 值。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> bar = <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Symbol</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'bar'</span>);
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> snaf = <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Symbol</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'snaf'</span>);
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">default</span> <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">myClass</span></span>{
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 公有方法</span>
  foo(baz) {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>[bar](baz);
}
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 私有方法</span>
  [bar](baz) {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>[snaf] = baz;
}
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ...</span>
};
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">上面代码中， bar 和 snaf 都是 Symbol 值，导致第三方无法获取到 它们，因此达到了私有方法和私有属性的效果。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">私有属性</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">与私有方法一样，ES6 不支持私有属性。目前，有一个提案，<br/>
为 class 加了私有属性。方法是在属性名之前，使用 # 表示。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;">class Point {
  #x;
constructor(x = 0) {
#x = +x; // 写成 this.#x 亦可
}
  get x() { return #x }
  set x(value) { #x = +value }
}
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">this 的指向</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">类的方法内部如果含有 this ，它默认指向类的实例。但是，必须非常<br/>
小心，一旦单独使用该方法，很可能报错。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Logger</span> </span>{
  printName(name = <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'there'</span>) {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>.print(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">`Hello <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">${name}</span>`</span>);
  }
  print(text) {
    <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(text);
} }
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> logger = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> Logger();
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> { printName } = logger;
printName(); <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// TypeError: Cannot read property 'print'</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">of</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">undefined</span>
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">一个比较简单的解决方法是，在构造方法中绑定 this ，这样就不会找 不到 print 方法了。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Logger</span> </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">constructor</span>() {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>.printName = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>.printName.bind(<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>);
  }
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ...</span>
}
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">另一种解决方法是使用箭头函数。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Logger</span> </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">constructor</span>() {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>.printName = <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">name = <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'there'</span></span>) =&gt;</span> {
      <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>.print(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">`Hello <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">${name}</span>`</span>);
}; }
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ...</span>
}
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">还有一种解决方法是使用 Proxy ，获取方法的时候，自动绑 定 this 。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">selfish</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">target</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> cache = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">WeakMap</span>();
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> handler = {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">get</span> (target, key) {
      <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> value = <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Reflect</span>.get(target, key);
      <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">if</span> (<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">typeof</span> value !== <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'function'</span>) {
        <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> value;
      }
      <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">if</span> (!cache.has(value)) {
        cache.set(value, value.bind(target));
}
      <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> cache.get(value);
    }
  };
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> proxy = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Proxy</span>(target, handler);
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> proxy;
}
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> logger = selfish(<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> Logger());
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">Class 的静态方法</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">类相当于实例的原型，所有在类中定义的方法，都会被实例继承。如果 在一个方法前，加上 static 关键字，就表示该方法不会被实例继承， 而是直接通过类来调用，这就称为“静态方法”。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Foo</span> </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">static</span> classMethod() {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'hello'</span>;
  }
}
Foo.classMethod() <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 'hello'</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> foo = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> Foo();
foo.classMethod()
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// TypeError: foo.classMethod is not a function</span>
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">注意，如果静态方法包含 this 关键字，这个 this 指的是类，而不是实例。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Foo</span> </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">static</span> bar () {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>.baz();
  }
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">static</span> baz () {
    <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'hello'</span>);
}
baz () {
    <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'world'</span>);
  }
}
Foo.bar() <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// hello</span>
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">从这个例子还可以看出，静态方法可以与非静态方法重名。<br/>
父类的静态方法，可以被子类继承。<br/>
静态方法也是可以从 super 对象上调用的。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">Class 的静态属性和实例属性</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">静态属性指的是 Class 本身的属性，即 Class.propName ，而不是定义<br/>
在实例对象( this )上的属性。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Foo</span> </span>{ }
Foo.prop = <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">1</span>;
Foo.prop <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 1</span>
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">上面的写法为 Foo 类定义了一个静态属性 prop 。 目前，只有这种写法可行，因为 ES6 明确规定，Class 内部只有静态方<br/>
法，没有静态属性。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 以下两种写法都无效 class Foo {</span>
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 写法一</span>
prop: <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">2</span>
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 写法二</span>
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">static</span> prop: <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">2</span>
}
Foo.prop <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// undefined</span>
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">new.target 属性</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">ES6 为 new 命令引入了一 个 new.target 属性，该属性一般用在构造函数之中，返回 new 命令 作用于的那个构造函数。如果构造函数不是通过 new 命令调用的， new.target 会返回 undefined ，因此这个属性可以用来确定构 造函数是怎么调用的。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Person</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">name</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">if</span> (<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span>.target !== <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">undefined</span>) {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>.name = name;
  } <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">else</span> {
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">throw</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Error</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'必须使用 new 命令生成实例'</span>); }
}
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 另一种写法</span>
<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Person</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">name</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">if</span> (<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span>.target === Person) {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">this</span>.name = name;
} <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">else</span> {
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">throw</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Error</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'必须使用 new 命令生成实例'</span>);
} }
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> person = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> Person(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'张三'</span>); <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 正确</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> notAPerson = Person.call(person, <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'张三'</span>); <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 报错</span>
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">Class 内部调用 new.target ，返回当前 Class。<br/>
需要注意的是，子类继承父类时， new.target 会返回子类。</p>
<h2 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 34px; border-bottom: 1px solid #dbdbdb; color: #333;">Class 的继承</h2>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">Class 可以通过 extends 关键字实现继承</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Point</span> </span>{
}
<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">ColorPoint</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">extends</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Point</span> </span>{
}
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">子类必须在 constructor 方法中调用 super 方法，否则新建实例时会 报错。这是因为子类没有自己的 this 对象，而是继承父类的 this 对 象，然后对其进行加工。如果不调用 super 方法，子类就得不<br/>
到 this 对象。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Point</span> </span>{ <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">/* ... */</span> }
<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">ColorPoint</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">extends</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Point</span> </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">constructor</span>() {
  }
}
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> cp = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> ColorPoint(); <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ReferenceError</span>
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">ES6 的继承机制完全，实质是先创造父类的实例对象 this (所以必须先调<br/>
用 super 方法)，然后再用子类的构造函数修改 this 。<br/>
如果子类没有定义 constructor 方法，这个方法会被默认添加，代码 如下。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">ColorPoint</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">extends</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Point</span> </span>{
}
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 等同于</span>
<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">ColorPoint</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">extends</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Point</span> </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">constructor</span>(...args) {
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">super</span>(...args);
} }
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">另一个需要注意的地方是，在子类的构造函数中，只有调用 super 之 后，才可以使用 this 关键字，否则会报错。这是因为子类实例的构 建，是基于对父类实例加工，只有 super 方法才能返回父类实例。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">类的 prototype 属性和__proto__属性</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">(1)子类的 <strong style="line-height: 160%; box-sizing: content-box; font-weight: 700;">proto</strong> 属性，表示构造函数的继承，总是指向父类。 (2)子类 prototype 属性的 <strong style="line-height: 160%; box-sizing: content-box; font-weight: 700;">proto</strong> 属性，表示方法的继承，总<br/>
是指向父类的 prototype 属性。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">A</span> </span>{ }
<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">B</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">extends</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">A</span> </span>{
}
B.__proto__ === A <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// true</span>
B.prototype.__proto__ === A.prototype <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// true</span>

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//类的继承是按照下面的模式实现的</span>
<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">A</span> </span>{ }
<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">B</span> </span>{ }
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// B 的实例继承 A 的实例</span>
<span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Object</span>.setPrototypeOf(B.prototype, A.prototype); <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// B 的实例继承 A 的静态属性</span>
<span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Object</span>.setPrototypeOf(B, A);
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> b = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> B();

<span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Object</span>.setPrototypeOf(B.prototype, A.prototype); <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 等同于</span>
B.prototype.__proto__ = A.prototype;
<span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Object</span>.setPrototypeOf(B, A); <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 等同于</span>
B.__proto__ = A;
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">extends 的继承目标</h4>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">B</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">extends</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">A</span> </span>{
}

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//上面代码的 A ，只要是一个有 prototype 属性的函数，就能被 B 继 承。由于函数都有 prototype 属性(除了 Function.prototype 函 数)，因此 A 可以是任意函数。</span>

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//下面，讨论三种特殊情况。</span>
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//第一种特殊情况，子类继承 Object 类。</span>
<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">A</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">extends</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Object</span> </span>{
}
A.__proto__ === <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Object</span> <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// true</span>
A.prototype.__proto__ === <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Object</span>.prototype <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// true</span>

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//第二种特殊情况，不存在任何继承。</span>
<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">A</span> </span>{ }
A.__proto__ === <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Function</span>.prototype <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// true</span>
A.prototype.__proto__ === <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Object</span>.prototype <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// true</span>

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//第三种特殊情况，子类继承 null 。</span>
<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">A</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">extends</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">null</span> </span>{
}
A.__proto__ === <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Function</span>.prototype <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// true</span>
A.prototype.__proto__ === <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">undefined</span> <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// true</span>
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">实例的 <strong style="line-height: 160%; box-sizing: content-box; font-weight: 700;">proto</strong> 属性</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">子类实例的 <strong style="line-height: 160%; box-sizing: content-box; font-weight: 700;">proto</strong> 属性的 <strong style="line-height: 160%; box-sizing: content-box; font-weight: 700;">proto</strong> 属性，指向父类实例<br/>
的 <strong style="line-height: 160%; box-sizing: content-box; font-weight: 700;">proto</strong> 属性。也就是说，子类的原型的原型，是父类的原型。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> p1 = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> Point(<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">2</span>, <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">3</span>);
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> p2 = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> ColorPoint(<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">2</span>, <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">3</span>, <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'red'</span>);
p2.__proto__ === p1.__proto__ <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// false</span>
p2.__proto__.__proto__ === p1.__proto__ <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// true</span>
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">extends 关键字不仅可以用来继承类，还可以 用来继承原生的构造函数。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">原生构造函数的继承</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">ECMAScript 的原生构造函数大致有下面这些：<br/>
Boolean()<br/>
Number()<br/>
String()<br/>
Array()<br/>
Date()<br/>
Function()<br/>
RegExp()<br/>
Error()<br/>
Object()</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">以前，这些原生构造函数是无法继承的。因为子类无法获得原生构造函数的内部属 性，通过 Array.apply() 或者分配给原型对象都不行。原生构造函数 会忽略 apply 方法传入的 this ，也就是说，原生构造函数的 this 无法绑定，导致拿不到内部属性。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">ES6 允许继承原生构造函数定义子类，因为 ES6 是先新建父类的实例对 象 this ，然后再用子类的构造函数修饰 this ，使得父类的所有行为 都可以继承。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">注意，继承 Object 的子类，有一个行为差异。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">class</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">NewObj</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">extends</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">Object</span></span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">constructor</span>(){
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">super</span>(...arguments);
  }
}
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> o = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">new</span> NewObj({<span style="color: #9cdcfe; line-height: 160%; box-sizing: content-box;">attr</span>: <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">true</span>});
o.attr === <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">true</span>  <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// false</span>
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">这是因为 ES6 改变了 Object 构造函数的行为，一 旦发现 Object 方法不是通过 new Object() 这种形式调用，ES6 规 定 Object 构造函数会忽略参数。</p>
<h2 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 34px; border-bottom: 1px solid #dbdbdb; color: #333;">Module 的语法</h2>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">ES6 模块的设计思想，是尽量的静态化，使得编译时就能确定模块的依 赖关系，以及输入和输出的变量</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// CommonJS模块</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> { stat, exists, readFile } = <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">require</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'fs'</span>);
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 等同于</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> _fs = <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">require</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'fs'</span>);
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> stat = _fs.stat;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> exists = _fs.exists;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">let</span> readfile = _fs.readfile;

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ES6模块</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span> { stat, exists, readFile } <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'fs'</span>;
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">由于 ES6 模块是编译时加载，使得静态分析成为可能。有了它，就能进 一步拓宽 JavaScript 的语法，比如引入宏(macro)和类型检验(type system)这些只能靠静态分析实现的功能。<br/>
除了静态加载带来的各种好处，ES6 模块还有以下好处。<br/>
不再需要 UMD 模块格式了，将来服务器和浏览器都会支持 ES6 模块 格式。目前，通过各种工具库，其实已经做到了这一点。<br/>
将来浏览器的新 API 就能用模块格式提供，不再必须做成全局变量 或者 navigator 对象的属性。<br/>
不再需要对象作为命名空间(比如 Math 对象)，未来这些功能可 以通过模块提供。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">严格模式</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">ES6 的模块自动采用严格模式，不管你有没有在模块头部加上 "use<br/>
strict"; 。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">export 命令</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">模块功能主要由两个命令构成: export 和 import 。 export 命令用<br/>
于规定模块的对外接口， import 命令用于输入其他模块提供的功能。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// profile.js</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> firstName = <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'Michael'</span>;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> lastName = <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'Jackson'</span>;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> year = <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">1958</span>;

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// profile.js</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> firstName = <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'Michael'</span>;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> lastName = <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'Jackson'</span>;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> year = <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">1958</span>;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> {firstName, lastName, year};

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//export 命令除了输出变量，还可以输出函数或类(class)。</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">multiply</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">x, y</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> x * y;
};
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">通常情况下， export 输出的变量就是本来的名字，但是可以使<br/>
用 as 关键字重命名。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">v1</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{ ... }
<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">v2</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{ ... }
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> {
  v1 <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">as</span> streamV1,
  v2 <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">as</span> streamV2,
  v2 <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">as</span> streamLatestVersion
};
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">需要特别注意的是， export 命令规定的是对外的接口，必须与模块内 部的变量建立一一对应关系。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 报错</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">1</span>;
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 报错</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> m = <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">1</span>;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> m;

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//正确的写法是下面这样</span>
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 写法一</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> m = <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">1</span>;
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 写法二</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> m = <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">1</span>;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> {m};
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 写法三</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> n = <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">1</span>;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> {n <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">as</span> m};
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">另外， export 语句输出的接口，与其对应的值是动态绑定关系，即通 过该接口，可以取到模块内部实时的值。</p>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">import 命令</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">使用 export 命令定义了模块的对外接口以后，其他 JS 文件就可以通<br/>
过 import 命令加载这个模块。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// main.js</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span> {firstName, lastName, year} <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./profile'</span>;
<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">setName</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">element</span>) </span>{
  element.textContent = firstName + <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">' '</span> + lastName;
}
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">如果想为输入的变量重新取一个名字， import 命令要使用 as 关键 字，将输入的变量重命名。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span> { lastName <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">as</span> surname } <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./profile'</span>;
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">import 命令具有提升效果，会提升到整个模块的头部，首先执行。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;">foo();
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span> { foo } <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'my_module'</span>;
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">目前阶段，通过 Babel 转码，CommonJS 模块的 require 命令和 ES6 模 块的 import 命令，可以写在同一个模块里面，<strong style="line-height: 160%; box-sizing: content-box; font-weight: 700;">但是最好不要这样做</strong>。 因为 import 在静态解析阶段执行，所以它是一个模块之中最早执行 的。下面的代码可能不会得到预期结果。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">require</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'core-js/modules/es6.symbol'</span>);
<span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">require</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'core-js/modules/es6.promise'</span>);
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span> React <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'React'</span>;
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">模块的整体加载</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">除了指定加载某个输出值，还可以使用整体加载，即用星号( * )指定 一个对象，所有输出值都加载在这个对象上面。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// circle.js</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">area</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">radius</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Math</span>.PI * radius * radius;
}
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">circumference</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">radius</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">2</span> * <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Math</span>.PI * radius;
}

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//逐一指定要加载的方法</span>
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// main.js</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span> { area, circumference } <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./circle'</span>;
<span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'圆面积:'</span> + area(<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">4</span>)); <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'圆周长:'</span> + circumference(<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">14</span>));

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//整体加载</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span> * <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">as</span> circle <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./circle'</span>;
<span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'圆面积:'</span> + circle.area(<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">4</span>)); <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'圆周长:'</span> + circle.circumference(<span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">14</span>));
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">模块整体加载所在的那个对象(上例是 circle )，应该是可以 静态分析的，所以不允许运行时改变。下面的写法都是不允许的。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span> * <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">as</span> circle <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./circle'</span>;
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 下面两行都是不允许的</span>
circle.foo = <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'hello'</span>;
circle.area = <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{};
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">export default 命令</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">export default 命令，为模块指定默认输出。<br/>
其他模块加载该模块时， import 命令可以为该匿名函数指定任意名 字。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// export-default.js</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">default</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> (<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'foo'</span>);
}

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// import-default.js</span>
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//这时就不需要知道原模块输出的函数名。需要注意的是，这时 import 命令后面，不使用大括号。</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span> customName <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./export-default'</span>;
customName(); <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 'foo'</span>
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">本质上， export default 就是输出一个叫做 default 的变量或方 法，然后系统允许你为它取任意名字。所以，下面的写法是有效的。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// modules.js</span>
<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">add</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">x, y</span>) </span>{
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> x * y; }
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> {add <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">as</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">default</span>}; <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 等同于</span>
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// export default add;</span>
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// app.js</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span> { <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">default</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">as</span> foo } <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'modules'</span>; <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 等同于</span>
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// import foo from 'modules';</span>
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">正是因为 export default 命令其实只是输出一个叫做 default 的变 量，所以它后面不能跟变量声明语句。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 正确</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> a = <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">1</span>;
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 正确</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> a = <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">1</span>;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">default</span> a;
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 错误</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">default</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> a = <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">1</span>;
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">export 与 import 的复合写法</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">如果在一个模块之中，先输入后输出同一个模块， import 语句可以<br/>
与 export 语句写在一起。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> { foo, bar } <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'my_module'</span>;
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 等同于</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span> { foo, bar } <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'my_module'</span>;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> { foo, bar };

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 接口改名</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> { foo <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">as</span> myFoo } <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'my_module'</span>;
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 整体输出</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> * <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'my_module'</span>;

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//默认接口的写法如下</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> { <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">default</span> } <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'foo'</span>;

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//具名接口改为默认接口的写法如下</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> { es6 <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">as</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">default</span> } <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./someModule'</span>;
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 等同于</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span> { es6 } <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./someModule'</span>;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">default</span> es6;

<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> { <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">default</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">as</span> es6 } <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./someModule'</span>;

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//下面三种 import 语句，没有对应的复合写法。</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span> * <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">as</span> someIdentifier <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">"someModule"</span>;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span> someIdentifier <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">"someModule"</span>;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span> someIdentifier, { namedIdentifier } <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span>
<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">"someModule"</span>;
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">模块的继承</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">模块之间也可以继承。<br/>
假设有一个 circleplus 模块，继承了 circle 模块。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// circleplus.js</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> * <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'circle'</span>;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">var</span> e = <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">2.71828182846</span>;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">default</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">x</span>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">return</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Math</span>.exp(x);
}
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">跨模块常量</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">const 声明的常量只在当前代码块 有效。如果想设置跨模块的常量(即跨多个文件)，或者说一个值要被 多个模块共享，可以采用下面的写法。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// constants.js 模块</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> A = <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">1</span>;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> B = <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">3</span>;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> C = <span style="color: #b8d7a3; line-height: 160%; box-sizing: content-box;">4</span>;
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// test1.js 模块</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span> * <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">as</span> constants <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./constants'</span>;
<span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(constants.A); <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 1</span>
<span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(constants.B); <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 3</span>
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// test2.js 模块</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span> {A, B} <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./constants'</span>;
<span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(A); <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 1</span>
<span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(B); <span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// 3</span>
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">如果要使用的常量非常多，可以建一个专门的 constants 目录，将各 种常量写在不同的文件里面，保存在该目录下。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// constants/db.js</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> db = {
  <span style="color: #9cdcfe; line-height: 160%; box-sizing: content-box;">url</span>: <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'http://my.couchdbserver.local:5984'</span>,
  <span style="color: #9cdcfe; line-height: 160%; box-sizing: content-box;">admin_username</span>: <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'admin'</span>,
  <span style="color: #9cdcfe; line-height: 160%; box-sizing: content-box;">admin_password</span>: <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'admin password'</span>
};
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// constants/user.js</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> users = [<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'root'</span>, <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'admin'</span>, <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'staff'</span>, <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'ceo'</span>,
<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'chief'</span>, <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'moderator'</span>];

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//然后，将这些文件输出的常量，合并在 index.js 里面。</span>
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// constants/index.js</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> {db} <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./db'</span>;
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">export</span> {users} <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./users'</span>;

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//使用的时候，直接加载 index.js 就可以了。</span>
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// script.js</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span> {db, users} <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">from</span> <span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./index'</span>;
</code></pre>
<h4 style="line-height: 160%; box-sizing: content-box; font-size: 20px; color: #333;">import()</h4>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">import 和 export 命令 只能在模块的顶层，不能在代码块之中(比如，在 if 代码块之中，或 在函数之中)。导致无法在运行时加载模块。在语法上，条件加载就不可能实现。如果 import 命令要取代 Node 的 require 方法，这就形成了一个障碍。因为 require 是运行 时加载模块， import 命令无法取代 require 的动态加载功能。<br/>
因此，有一个提案，建议引入 import() 函数，完成动态加载。</p>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">import 命令能够接受什么参数， import() 函数就能接受什 么参数，两者区别主要是后者为动态加载。<br/>
import() 返回一个 Promise 对象。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> main = <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">document</span>.querySelector(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'main'</span>);
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">`./section-modules/<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">${someVariable}</span>.js`</span>)
  .then(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">module</span> =&gt;</span> {
    <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">module</span>.loadPageInto(main);
  })
  .catch(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">err</span> =&gt;</span> {
    main.textContent = err.message;
});
</code></pre>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">import() 函数可以用在任何地方，不仅仅是模块，非模块的脚本也可 以使用。它是运行时执行，也就是说，什么时候运行到这一句，也会加 载指定的模块。另外， import() 函数与所加载的模块没有静态连接关 系，这点也是与 import 语句不相同。<br/>
import() 类似于 Node 的 require 方法，区别主要是前者是异步加 载，后者是同步加载。</p>
<h5 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 16px; color: #333;">适用场合</h5>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">(1)按需加载。<br/>
(2)条件加载。<br/>
(3)动态的模块路径。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//根据函数 f 的返回结果，加载不同的模块。</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span>(f())
.then(...);
</code></pre>
<h5 style="line-height: 160%; box-sizing: content-box; font-weight: 700; font-size: 16px; color: #333;">注意点</h5>
<p style="line-height: 160%; box-sizing: content-box; margin: 10px 0; color: #333;">import() 加载模块成功以后，这个模块会作为一个对象，当<br/>
作 then 方法的参数。因此，可以使用对象解构赋值的语法，获取输出 接口。</p>
<pre style="line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; margin: 2px 0 8px; background-color: #f5f7f8;"><code style="display: block; overflow-x: auto; background: #1e1e1e; line-height: 160%; box-sizing: content-box; border: 0; border-radius: 0; letter-spacing: -.3px; padding: 18px; color: #f4f4f4; white-space: pre-wrap;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./myModule.js'</span>)
.then(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">{export1, export2}</span>) =&gt;</span> {
<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">// ...·</span>
});

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//如果模块有 default 输出接口，可以用参数直接获得</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./myModule.js'</span>)
.then(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">myModule</span> =&gt;</span> {
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(myModule.default);
});

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//上面的代码也可以使用具名输入的形式。</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./myModule.js'</span>)
.then(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">{<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">default</span>: theDefault}</span>) =&gt;</span> {
  <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">console</span>.log(theDefault);
});

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//如果想同时加载多个模块，可以采用下面的写法。</span>
<span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Promise</span>.all([
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./module1.js'</span>),
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./module2.js'</span>),
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./module3.js'</span>),
])
.then(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">[module1, module2, module3]</span>) =&gt;</span> {
··· });

<span style="color: #57a64a; font-style: italic; line-height: 160%; box-sizing: content-box;">//import() 也可以用在 async 函数之中。</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">async</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"><span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">function</span> <span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;">main</span>(<span style="color: #dcdcdc; line-height: 160%; box-sizing: content-box;"/>) </span>{
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> myModule = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">await</span> <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./myModule.js'</span>);
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> {export1, export2} = <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">await</span>
<span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./myModule.js'</span>);
  <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">const</span> [module1, module2, module3] =
    <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">await</span> <span style="color: #4ec9b0; line-height: 160%; box-sizing: content-box;">Promise</span>.all([
      <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./module1.js'</span>),
      <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./module2.js'</span>),
      <span style="color: #569cd6; line-height: 160%; box-sizing: content-box;">import</span>(<span style="color: #d69d85; line-height: 160%; box-sizing: content-box;">'./module3.js'</span>),
]); }
main();
</code></pre>
</div><center style="display:none !important;visibility:collapse !important;height:0 !important;white-space:nowrap;width:100%;overflow:hidden">%23%23%20Reflect%0A%20%20%20%20%20%20%20%20Reflect%E5%AF%B9%E8%B1%A1%E5%92%8CProxy%E5%AF%B9%E8%B1%A1%E4%B8%80%E6%A0%B7%EF%BC%8C%E9%83%BD%E6%98%AFES6%E4%B8%BA%E4%BA%86%E6%93%8D%E4%BD%9C%E5%AF%B9%E8%B1%A1%E8%80%8C%E6%8F%90%E4%BE%9B%E7%9A%84API%E3%80%82%0A%23%23%23%23%20%E8%AE%BE%E8%AE%A1%E7%9B%AE%E7%9A%84%EF%BC%9A%0A**1%E3%80%81%E6%9B%BF%E4%BB%A3Object%E3%80%82%E5%B0%86Object%E4%B8%8A%E7%9A%84%E5%8E%9F%E6%9D%A5%E7%9A%84%E6%96%B9%E6%B3%95%E9%83%A8%E7%BD%B2%E5%88%B0Reflect%E4%B8%8A%EF%BC%8C%E5%B9%B6%E4%B8%94%E4%B9%8B%E5%90%8E%E6%96%B0%E5%A2%9E%E6%96%B9%E6%B3%95%E4%B9%9F%E5%8F%AA%E9%83%A8%E7%BD%B2%E5%88%B0Reflect%E5%AF%B9%E8%B1%A1%E4%B8%8A%E3%80%82**%0A%20%20%20%20%20%20%20%202%E3%80%81%E8%AE%A9%E4%B9%8B%E5%89%8DObject%E6%9F%90%E4%BA%9B%E6%96%B9%E6%B3%95%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%E6%9B%B4%E5%8A%A0%E5%90%88%E7%90%86%E3%80%82%0A%20%20%20%20%20%20%20%203%E3%80%81%E8%AE%A9Object%E7%9A%84%E6%93%8D%E4%BD%9C%E5%8F%98%E6%88%90%E5%87%BD%E6%95%B0%E8%A1%8C%E4%B8%BA%E3%80%82%0A%20%20%20%20%20%20%20%20**4%E3%80%81%E4%B8%8EProxy%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%96%B9%E6%B3%95%E4%B8%80%E4%B8%80%E5%AF%B9%E5%BA%94%EF%BC%88Proxy%E5%8F%AF%E4%BB%A5%E4%BF%AE%E6%94%B9%E5%AF%B9%E8%B1%A1%E7%9A%84%E8%A1%8C%E4%B8%BA%EF%BC%8C%E8%80%8CReflect%E5%8F%AF%E4%BB%A5%E6%89%BE%E5%9B%9E%E5%AF%B9%E8%B1%A1%E7%9A%84%E9%BB%98%E8%AE%A4%E8%A1%8C%E4%B8%BA%EF%BC%89%E3%80%82**%0A%23%23%23%23%20%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%EF%BC%9A%0A%201%E3%80%81Reflect.apply(target%2CthisArg%2Cargs)%2F%2F%E7%BB%91%E5%AE%9Athis%E5%AF%B9%E8%B1%A1%E5%90%8E%E6%89%A7%E8%A1%8C%E7%BB%99%E5%AE%9A%E5%87%BD%E6%95%B0%0A%20%20%20%20%20%20%20%202%E3%80%81Reflect.construct(target%2Cargs)%2F%2F%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%0A%20%20%20%20%20%20%20%203%E3%80%81Reflect.get(target%2Cname%2Creceiver)%2F%2F%E6%9F%A5%E6%89%BE%E5%B9%B6%E8%BF%94%E5%9B%9Etarget%E5%AF%B9%E8%B1%A1%E4%B8%8A%E7%9A%84name%E5%B1%9E%E6%80%A7%EF%BC%8C%E6%89%BE%E4%B8%8D%E5%88%B0%E8%BF%94%E5%9B%9Eundefined%0A%20%20%20%20%20%20%20%204%E3%80%81Reflect.set(target%2Cname%2Cvalue%2Creceiver)%2F%2F%E8%AE%BE%E7%BD%AEtarget%E5%AF%B9%E8%B1%A1%E4%B8%8A%E7%9A%84name%E5%B1%9E%E6%80%A7%E4%B8%BAvalue%0A%20%20%20%20%20%20%20%205%E3%80%81Reflect.defineProperty(target%2Cname%2Cdesc)%2F%2F%E7%BB%99%E5%AF%B9%E8%B1%A1%E5%AE%9A%E4%B9%89%E5%B1%9E%E6%80%A7%0A%20%20%20%20%20%20%20%206%E3%80%81Reflect.deleteProperty(target%2Cname)%2F%2F%E5%88%A0%E9%99%A4target%E5%AF%B9%E8%B1%A1%E4%B8%8A%E7%9A%84name%E5%B1%9E%E6%80%A7%0A%20%20%20%20%20%20%20%207%E3%80%81Reflect.has(target%2Cname)%2F%2F%E6%9F%A5%E6%89%BEname%E5%B1%9E%E6%80%A7%E6%98%AF%E5%90%A6%E5%B1%9E%E4%BA%8Etarget%E5%AF%B9%E8%B1%A1%0A%20%20%20%20%20%20%20%208%E3%80%81Reflect.ownKeys(target)%2F%2F%E8%BF%94%E5%9B%9E%E5%AF%B9%E8%B1%A1%E6%89%80%E6%9C%89%E5%B1%9E%E6%80%A7%0A%20%20%20%20%20%20%20%209%E3%80%81Reflect.isExtensible(target)%2F%2F%E5%88%A4%E6%96%AD%E5%BD%93%E5%89%8D%E5%AF%B9%E8%B1%A1%E6%98%AF%E5%90%A6%E5%8F%AF%E6%89%A9%E5%B1%95%0A%20%20%20%20%20%20%20%2010%E3%80%81Reflect.preventExtensions(target)%2F%E5%B0%86%E5%AF%B9%E8%B1%A1%E5%8F%98%E4%B8%BA%E4%B8%8D%E5%8F%AF%E6%89%A9%E5%B1%95%0A%20%20%20%20%20%20%20%2011%E3%80%81Reflect.getOwnPropertyDescriptor(target%2Cname)%2F%2F%E5%BE%97%E5%88%B0%E6%8C%87%E5%AE%9A%E5%B1%9E%E6%80%A7%E7%9A%84%E6%8F%8F%E8%BF%B0%E5%AF%B9%E8%B1%A1%0A%20%20%20%20%20%20%20%2012%E3%80%81Reflect.getPrototypeOf(target)%2F%2F%E8%AF%BB%E5%8F%96target%E5%AF%B9%E8%B1%A1%E4%B8%8A%E7%9A%84__proto__%E5%B1%9E%E6%80%A7%0A%20%20%20%20%20%20%20%2013%E3%80%81Reflect.setPrototypeOf(target%2C%20prototype)%2F%2F%E8%AE%BE%E7%BD%AEtarget%E5%AF%B9%E8%B1%A1%E4%B8%8A%E7%9A%84__proto__%E5%B1%9E%E6%80%A7%0A%0A%0A%23%23%20Promise%E5%AF%B9%E8%B1%A1%0A%20%20%20%20%20%20%20%20Promise%E6%98%AF%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B%E7%9A%84%E4%B8%80%E7%A7%8D%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%EF%BC%8C%E7%9B%B8%E6%AF%94%E5%9B%9E%E8%B0%83%E5%92%8C%E4%BA%8B%E4%BB%B6%E6%9B%B4%E5%90%88%E7%90%86%E5%92%8C%E5%BC%BA%E5%A4%A7%E3%80%82%E5%AE%83%E5%83%8F%E4%B8%80%E4%B8%AA%E5%AE%B9%E5%99%A8%EF%BC%8C%E9%87%8C%E9%9D%A2%E4%BF%9D%E5%AD%98%E7%9D%80%E6%9C%AA%E6%9D%A5%E6%89%8D%E4%BC%9A%E7%BB%93%E6%9D%9F%E7%9A%84%E4%BA%8B%E4%BB%B6%EF%BC%88%E9%80%9A%E5%B8%B8%E6%98%AF%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%EF%BC%89%E7%9A%84%E7%BB%93%E6%9E%9C%E3%80%82%0A%23%23%23%23%20%20%20%E7%89%B9%E7%82%B9%EF%BC%9A%0A1%E3%80%81%E5%AF%B9%E8%B1%A1%E7%8A%B6%E6%80%81%E4%B8%8D%E5%8F%97%E5%A4%96%E7%95%8C%E5%BD%B1%E5%93%8D%E3%80%82%E6%9C%89%E4%BB%A5%E4%B8%8B3%E7%A7%8D%E7%8A%B6%E6%80%81%EF%BC%9Apending(%E8%BF%9B%E8%A1%8C%E4%B8%AD)%E3%80%81fulfilled(%E5%B7%B2%E6%88%90%E5%8A%9F)%E3%80%81%20rejected(%E5%B7%B2%E5%A4%B1%E8%B4%A5)%E3%80%82%E5%8F%AA%E5%8F%97%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%E7%BB%93%E6%9E%9C%E5%BD%B1%E5%93%8D%E3%80%82%0A%20%20%20%20%20%20%20%202%E3%80%81%E7%8A%B6%E6%80%81%E6%94%B9%E5%8F%98%E5%90%8E%E5%B0%B1%E4%B8%8D%E4%BC%9A%E5%86%8D%E5%8F%98%EF%BC%8C%E4%BB%BB%E4%BD%95%E6%97%B6%E5%80%99%E9%83%BD%E5%8F%AF%E4%BB%A5%E5%BE%97%E5%88%B0%E8%BF%99%E4%B8%AA%E7%BB%93%E6%9E%9C%E3%80%82%EF%BC%88%E4%BA%8B%E4%BB%B6%E9%94%99%E8%BF%87%E5%90%8E%E5%86%8D%E7%9B%91%E5%90%AC%E5%B0%B1%E6%97%A0%E6%95%88%EF%BC%8C%E4%BD%86%E6%98%AFPromise%E5%AF%B9%E8%B1%A1%E7%8A%B6%E6%80%81%E5%8F%98%E6%9B%B4%E5%90%8E%EF%BC%8C%E5%86%8D%E5%AF%B9%E5%AE%83%E8%AE%BE%E7%BD%AE%E5%9B%9E%E8%B0%83%EF%BC%8C%E4%B9%9F%E4%BC%9A%E5%BE%97%E5%88%B0%E7%BB%93%E6%9E%9C%EF%BC%89%E3%80%82%0A%23%23%23%23%20%20%20%20%E7%BC%BA%E7%82%B9%EF%BC%9A%0A%201%E3%80%81%E4%B8%80%E6%97%A6%E6%96%B0%E5%BB%BA%E5%AE%83%E4%BC%9A%E7%AB%8B%E5%8D%B3%E6%89%A7%E8%A1%8C%EF%BC%8C%E4%B8%AD%E9%80%94%E4%B8%8D%E8%83%BD%E5%8F%96%E6%B6%88%E3%80%82%0A%20%20%20%20%20%20%20%202%E3%80%81%E5%A6%82%E6%9E%9C%E4%B8%8D%E8%AE%BE%E7%BD%AE%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%EF%BC%8CPromise%E5%86%85%E9%83%A8%E6%8A%9B%E5%87%BA%E7%9A%84%E9%94%99%E8%AF%AF%EF%BC%8C%E4%B8%8D%E4%BC%9A%E5%8F%8D%E5%BA%94%E5%88%B0%E5%A4%96%E9%83%A8%E3%80%82%0A%20%20%20%20%20%20%20%203%E3%80%81%E5%BD%93%E5%A4%84%E4%BA%8Epending%E7%8A%B6%E6%80%81%E6%97%B6%EF%BC%8C%E6%97%A0%E6%B3%95%E5%BE%97%E7%9F%A5%E7%9B%AE%E5%89%8D%E8%BF%9B%E5%B1%95%E5%88%B0%E5%93%AA%E4%B8%80%E9%98%B6%E6%AE%B5%E3%80%82%0A%23%23%23%23%20%20%20%20%20%E5%9F%BA%E6%9C%AC%E7%94%A8%E6%B3%95%EF%BC%9A%0APromise%E5%AF%B9%E8%B1%A1%E6%98%AF%E4%B8%80%E4%B8%AA%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%EF%BC%8C%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8new%E7%94%9F%E6%88%90%E4%B8%80%E4%B8%AAPromise%E5%AE%9E%E4%BE%8B%E3%80%82%0A%20%20%20%20%20%20%20%20Promise%E5%9C%A8%E6%96%B0%E5%BB%BA%E5%90%8E%E7%AB%8B%E5%8D%B3%E6%89%A7%E8%A1%8C%EF%BC%8Cthen%E6%96%B9%E6%B3%95%E6%8C%87%E5%AE%9A%E7%9A%84%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%EF%BC%8C%E5%B0%86%E5%9C%A8%E5%BD%93%E5%89%8D%E8%84%9A%E6%9C%AC%E6%89%80%E6%9C%89%E5%90%8C%E6%AD%A5%E4%BB%BB%E5%8A%A1%E6%89%A7%E8%A1%8C%E5%AE%8C%E4%B9%8B%E5%90%8E%E6%89%8D%E4%BC%9A%E6%89%A7%E8%A1%8C%E3%80%82%0A%20%20%20%20%20%20%20%20%E5%BD%93%E4%B8%80%E4%B8%AA%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C(p2)%E7%9A%84%E7%BB%93%E6%9E%9C%E8%BF%94%E5%9B%9E%E6%98%AF%E5%8F%A6%E4%B8%80%E4%B8%AA%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C(p1)%E6%97%B6%EF%BC%8Cp1%E7%9A%84%E7%8A%B6%E6%80%81%E5%86%B3%E5%AE%9A%E4%BA%86p2%E7%9A%84%E7%8A%B6%E6%80%81%E3%80%82%0A%20%20%20%20%20%20%20%20%E8%B0%83%E7%94%A8resolve%E6%88%96reject%E5%B9%B6%E4%B8%8D%E4%BC%9A%E7%BB%88%E7%BB%93Promise%E5%8F%82%E6%95%B0%E5%87%BD%E6%95%B0%E7%9A%84%E6%89%A7%E8%A1%8C%E3%80%82%0A%0A%23%23%23%23%20Promise.prototype.then()%0Athen%E6%96%B9%E6%B3%95%E8%BF%94%E5%9B%9E%E7%9A%84%E6%98%AF%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84Promise%E5%AE%9E%E4%BE%8B(%E4%B8%8D%E6%98%AF%E5%8E%9F%E6%9D%A5%E6%98%AFPromise%E5%AE%9E%E4%BE%8B)%E3%80%82%E5%9B%A0%E6%AD%A4%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E9%93%BE%E5%BC%8F%E5%86%99%E6%B3%95%E3%80%82%E5%8D%B3%E5%9C%A8then%E6%96%B9%E6%B3%95%E5%90%8E%E5%86%8D%E8%B7%9F%E5%8F%A6%E4%B8%80%E4%B8%AAthen%E6%96%B9%E6%B3%95%E3%80%82%0A%20%20%20%20%20%20%20%20%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%8F%82%E6%95%B0%E6%98%AFresolved%E7%8A%B6%E6%80%81%E7%9A%84%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%EF%BC%8C%E7%AC%AC%E4%BA%8C%E4%B8%AA%E5%8F%82%E6%95%B0(%E5%8F%AF%E9%80%89)%E6%98%AFrejected%E7%8A%B6%E6%80%81%E7%9A%84%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E3%80%82%0A%23%23%23%23%20%20%20%20%20Promise.prototype.catch()%0A%20%E6%8D%95%E8%8E%B7%E5%89%8D%E9%9D%A2%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%E3%80%81then%E6%96%B9%E6%B3%95%E3%80%81catch%E6%96%B9%E6%B3%95%E6%8A%9B%E5%87%BA%E7%9A%84%E9%94%99%E8%AF%AF%E3%80%82%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%E7%9A%84reject%E6%96%B9%E6%B3%95%E7%AD%89%E5%90%8C%E4%BA%8E%E6%8A%9B%E5%87%BA%E9%94%99%E8%AF%AF(%E4%B9%9F%E4%BC%9A%E8%A2%ABcatch%E6%8D%95%E8%8E%B7)%EF%BC%8C%E5%A6%82%E6%9E%9C%E5%B7%B2%E7%BB%8F%E7%8A%B6%E6%80%81%E5%B7%B2%E7%BB%8F%E5%8F%98%E6%88%90resolved%EF%BC%8C%E5%86%8D%E6%8A%9B%E5%87%BA%E9%94%99%E8%AF%AF%E6%98%AF%E6%97%A0%E6%95%88%E3%80%82(%E5%BB%BA%E8%AE%AE%E4%BD%BF%E7%94%A8catch%E6%96%B9%E6%B3%95%EF%BC%8C%E8%80%8C%E4%B8%8D%E4%BD%BF%E7%94%A8then%E6%96%B9%E6%B3%95%E7%9A%84%E7%AC%AC%E4%BA%8C%E4%B8%AA%E5%8F%82%E6%95%B0)%0A%23%23%23%23%20%20%20%20%20Promise.all()%0A%E5%B0%86%E5%A4%9A%E4%B8%AAPromise%E5%AE%9E%E4%BE%8B%EF%BC%8C%E5%8C%85%E8%A3%85%E6%88%90%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84Promise%E5%AE%9E%E4%BE%8B%E3%80%82var%20p%20%3D%20Promise.all(%5Bp1%2Cp2%2Cp3%5D)%3B%0A%20%20%20%20%20%20%20%20p%E7%9A%84%E7%8A%B6%E6%80%81%E7%94%B1p1%2Cp2%2Cp3%E5%86%B3%E5%AE%9A%EF%BC%9A%0A%20%20%20%20%20%20%20%201)%E3%80%81%E5%8F%AA%E6%9C%89p1%2Cp2%2Cp3%E7%9A%84%E7%8A%B6%E6%80%81%E9%83%BD%E5%8F%98%E6%88%90fulfilled%2Cp%E7%9A%84%E7%8A%B6%E6%80%81%E6%89%8D%E4%BC%9A%E5%8F%98%E6%88%90fulfilled%E3%80%82%0A%20%20%20%20%20%20%20%202)%E3%80%81%E5%8F%AA%E8%A6%81p1%2Cp2%2Cp3%E4%B9%8B%E4%B8%AD%E6%9C%89%E4%B8%80%E4%B8%AA%E8%A2%ABrejected%2Cp%E7%9A%84%E7%8A%B6%E6%80%81%E5%B0%B1%E4%BC%9A%E5%8F%98%E6%88%90rejected%EF%BC%8C%E6%AD%A4%E6%97%B6%E7%AC%AC%E4%B8%80%E4%B8%AAreject%E7%9A%84%E5%AE%9E%E4%BE%8B%E7%9A%84%E8%BF%94%E5%9B%9E%E5%80%BC%EF%BC%8C%E4%BC%9A%E4%BC%A0%E9%80%92%E7%BB%99p%E7%9A%84%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E3%80%82%0A%23%23%23%23%20Promise.race()%0A%E5%B0%86%E5%A4%9A%E4%B8%AAPromise%E5%AE%9E%E4%BE%8B%EF%BC%8C%E5%8C%85%E8%A3%85%E6%88%90%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84Promise%E5%AE%9E%E4%BE%8B%E3%80%82var%20p%20%3D%20Promise.race(%5Bp1%2Cp2%2Cp3%5D)%3B%0A%20%20%20%20%20%20%20%20p%E7%9A%84%E7%8A%B6%E6%80%81%E7%94%B1p1%2Cp2%2Cp3%E5%86%B3%E5%AE%9A%EF%BC%9A%0A%20%20%20%20%20%20%20%20%20%20%20%20%E5%8F%AA%E8%A6%81p1%2Cp2%2Cp3%E4%B9%8B%E4%B8%AD%E6%9C%89%E4%B8%80%E4%B8%AA%E5%AE%9E%E4%BE%8B%E7%8E%87%E5%85%88%E6%94%B9%E5%8F%98%E7%8A%B6%E6%80%81%EF%BC%8Cp%E7%9A%84%E7%8A%B6%E6%80%81%E5%B0%B1%E8%B7%9F%E7%9D%80%E6%94%B9%E5%8F%98%E3%80%82%E9%82%A3%E4%B8%AA%E7%8E%87%E5%85%88%E6%94%B9%E5%8F%98%E7%9A%84Promise%E5%AE%9E%E4%BE%8B%E7%9A%84%E8%BF%94%E5%9B%9E%E5%80%BC%EF%BC%8C%E5%B0%B1%E4%BC%A0%E9%80%92%E7%BB%99p%E7%9A%84%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E3%80%82%0A%23%23%23%23%20Promise.resolve()%0A%20%E5%B0%86%E7%8E%B0%E6%9C%89%E5%AF%B9%E8%B1%A1%E8%BD%AC%E4%B8%BAPromise%E5%AF%B9%E8%B1%A1%E3%80%82%0A%20%20%20%20%20%20%20%20resolve%E6%96%B9%E6%B3%95%E7%9A%84%E5%8F%82%E6%95%B0%E5%88%86%E4%B8%BA%E5%9B%9B%E7%A7%8D%E6%83%85%E5%86%B5%EF%BC%9A%0A%20%20%20%20%20%20%20%20%20%20%20%201)%E3%80%81%E5%8F%82%E6%95%B0%E6%98%AF%E4%B8%80%E4%B8%AAPromise%E5%AE%9E%E4%BE%8B%E3%80%82%E7%9B%B4%E6%8E%A5%E8%BF%94%E5%9B%9E%E8%BF%99%E4%B8%AA%E5%AE%9E%E4%BE%8B%0A%20%20%20%20%20%20%20%20%20%20%20%202)%E3%80%81%E5%8F%82%E6%95%B0%E6%98%AF%E4%B8%80%E4%B8%AA%E5%85%B7%E6%9C%89then%E6%96%B9%E6%B3%95%E7%9A%84%E5%AF%B9%E8%B1%A1%E3%80%82%E5%B0%86%E8%BF%99%E5%AF%B9%E8%B1%A1%E8%BD%AC%E6%8D%A2%E4%B8%BAPromise%E5%AF%B9%E8%B1%A1%EF%BC%8C%E7%84%B6%E5%90%8E%E7%AB%8B%E5%8D%B3%E6%89%A7%E8%A1%8Cthen%E6%96%B9%E6%B3%95%EF%BC%8C%E7%84%B6%E5%90%8E%E7%8A%B6%E6%80%81%E6%94%B9%E4%B8%BAresolved%E3%80%82%0A%20%20%20%20%20%20%20%20%20%20%20%203)%E3%80%81%E5%8F%82%E6%95%B0%E4%B8%8D%E5%85%B7%E6%9C%89then%E6%96%B9%E6%B3%95%E6%88%96%E8%80%85%E6%A0%B9%E6%9C%AC%E4%B8%8D%E6%98%AF%E5%AF%B9%E8%B1%A1%E3%80%82%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84Promise%E5%AF%B9%E8%B1%A1%EF%BC%8C%E7%8A%B6%E6%80%81%E4%B8%BAresolved%EF%BC%8C%E5%B9%B6%E5%B0%86%E5%8F%82%E6%95%B0%E4%BC%A0%E7%BB%99%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E3%80%82%0A%20%20%20%20%20%20%20%20%20%20%20%204)%E3%80%81%E4%B8%8D%E5%B8%A6%E6%9C%89%E4%BB%BB%E4%BD%95%E5%8F%82%E6%95%B0%E3%80%82%E7%9B%B4%E6%8E%A5%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AAresolved%E7%8A%B6%E6%80%81%E7%9A%84Promise%E5%AF%B9%E8%B1%A1%E3%80%82%0A%23%23%23%23%20%20Promise.reject()%0A%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84Promise%E5%AE%9E%E4%BE%8B%EF%BC%8C%E8%AF%A5%E5%AE%9E%E4%BE%8B%E7%8A%B6%E6%80%81%E4%B8%BArejected%E3%80%82%E5%8F%82%E6%95%B0%E4%BC%9A%E4%BC%A0%E7%BB%99%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E3%80%82%0A%20%20%20%20%E9%99%84%E5%8A%A0%E6%96%B9%E6%B3%95%0A%20%20%20%20%20%20%20%20done()%EF%BC%9A%E6%80%BB%E6%98%AF%E5%A4%84%E4%BA%8E%E5%9B%9E%E8%B0%83%E9%93%BE%E7%9A%84%E5%B0%BE%E7%AB%AF%EF%BC%8C%E4%BF%9D%E8%AF%81%E6%8A%9B%E5%87%BA%E4%BB%BB%E4%BD%95%E5%8F%AF%E8%83%BD%E5%87%BA%E7%8E%B0%E7%9A%84%E9%94%99%E8%AF%AF%E3%80%82%0A%20%20%20%20%20%20%20%20finally()%EF%BC%9A%E4%B8%8D%E7%AE%A1%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%E7%8A%B6%E6%80%81%E6%98%AF%E4%BB%80%E4%B9%88%E9%83%BD%E4%BF%9D%E8%AF%81%E6%89%A7%E8%A1%8C%E3%80%82%0A%23%23%23%23%20Promise.try()%0A%20%E5%BD%93%E4%B8%8D%E7%9F%A5%E9%81%93%E6%88%96%E8%80%85%E4%B8%8D%E6%83%B3%E5%8C%BA%E5%88%86%E5%87%BD%E6%95%B0f%E6%98%AF%E5%90%8C%E6%AD%A5%E5%87%BD%E6%95%B0%E8%BF%98%E6%98%AF%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%EF%BC%8C%E4%BD%86%E6%98%AF%E6%83%B3%E7%94%A8Promise%E6%9D%A5%E5%A4%84%E7%90%86%E5%AE%83%EF%BC%8C%E7%94%A8then%E5%92%8Ccatch%E5%90%8C%E4%B8%80%E5%A4%84%E7%90%86%E3%80%82%0Atry%20%7B%0A%20%20database.users.get(%7Bid%3A%20userId%7D)%0A%20%20.then(...)%0A%20%20.catch(...)%0A%7D%20catch%20(e)%20%7B%0A%20%20%2F%2F%20...%0A%7D%E4%B8%8A%E9%9D%A2%E8%BF%99%E6%A0%B7%E7%9A%84%E5%86%99%E6%B3%95%E5%B0%B1%E5%BE%88%E7%AC%A8%E6%8B%99%E4%B8%8A%E9%9D%A2%E8%BF%99%E6%A0%B7%E7%9A%84%E5%86%99%E6%B3%95%E5%B0%B1%E5%BE%88%E7%AC%A8%E6%8B%99Promise%20%E6%98%AF%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B%E7%9A%84%E4%B8%80%E7%A7%8D%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%EF%BC%8C%E6%AF%94%E4%BC%A0%E7%BB%9F%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%E2%80%94%E2%80%94%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E5%92%8C%20%E4%BA%8B%E4%BB%B6%E2%80%94%E2%80%94%E6%9B%B4%E5%90%88%E7%90%86%E5%92%8C%E6%9B%B4%E5%BC%BA%E5%A4%A7%0A%23%23%20Iterator%20%E5%92%8C%20for...of%20%E5%BE%AA%E7%8E%AF%0A%0A%E9%81%8D%E5%8E%86%E5%99%A8(Iterator)%E6%98%AF%E4%B8%80%E7%A7%8D%E6%8E%A5%E5%8F%A3%EF%BC%8C%E4%B8%BA%E5%90%84%E7%A7%8D%E4%B8%8D%E5%90%8C%E7%9A%84%E6%95%B0%20%E6%8D%AE%E7%BB%93%E6%9E%84%E6%8F%90%E4%BE%9B%E7%BB%9F%E4%B8%80%E7%9A%84%E8%AE%BF%E9%97%AE%E6%9C%BA%E5%88%B6%E3%80%82%E4%BB%BB%E4%BD%95%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%8F%AA%E8%A6%81%E9%83%A8%E7%BD%B2Iterator%E6%8E%A5%E5%8F%A3%EF%BC%8C%E5%B0%B1%E5%8F%AF%20%E4%BB%A5%E5%AE%8C%E6%88%90%E9%81%8D%E5%8E%86%E6%93%8D%E4%BD%9C(%E5%8D%B3%E4%BE%9D%E6%AC%A1%E5%A4%84%E7%90%86%E8%AF%A5%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E7%9A%84%E6%89%80%E6%9C%89%E6%88%90%E5%91%98)%E3%80%82%0A%0AIterator%20%E7%9A%84%E4%BD%9C%E7%94%A8%E6%9C%89%E4%B8%89%E4%B8%AA%3A%0A%E4%B8%80%E6%98%AF%E4%B8%BA%E5%90%84%E7%A7%8D%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%EF%BC%8C%E6%8F%90%E4%BE%9B%E4%B8%80%E4%B8%AA%E7%BB%9F%E4%B8%80%E7%9A%84%E3%80%81%E7%AE%80%E4%BE%BF%E7%9A%84%20%E8%AE%BF%E9%97%AE%E6%8E%A5%E5%8F%A3%3B%0A%E4%BA%8C%E6%98%AF%E4%BD%BF%E5%BE%97%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E7%9A%84%E6%88%90%E5%91%98%E8%83%BD%E5%A4%9F%E6%8C%89%E6%9F%90%E7%A7%8D%E6%AC%A1%E5%BA%8F%E6%8E%92%E5%88%97%3B%0A%E4%B8%89%E6%98%AFES6%E5%88%9B%20%E9%80%A0%E4%BA%86%E4%B8%80%E7%A7%8D%E6%96%B0%E7%9A%84%E9%81%8D%E5%8E%86%E5%91%BD%E4%BB%A4%20for...of%20%E5%BE%AA%E7%8E%AF%EF%BC%8CIterator%E6%8E%A5%E5%8F%A3%E4%B8%BB%E8%A6%81%0A%E4%BE%9B%20for...of%20%E6%B6%88%E8%B4%B9%E3%80%82%0A%0AIterator%20%E7%9A%84%E9%81%8D%E5%8E%86%E8%BF%87%E7%A8%8B%E6%98%AF%E8%BF%99%E6%A0%B7%E7%9A%84%E3%80%82%0A(1)%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E6%8C%87%E9%92%88%E5%AF%B9%E8%B1%A1%EF%BC%8C%E6%8C%87%E5%90%91%E5%BD%93%E5%89%8D%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E7%9A%84%E8%B5%B7%E5%A7%8B%E4%BD%8D%E7%BD%AE%E3%80%82%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%EF%BC%8C%E9%81%8D%20%E5%8E%86%E5%99%A8%E5%AF%B9%E8%B1%A1%E6%9C%AC%E8%B4%A8%E4%B8%8A%EF%BC%8C%E5%B0%B1%E6%98%AF%E4%B8%80%E4%B8%AA%E6%8C%87%E9%92%88%E5%AF%B9%E8%B1%A1%E3%80%82%0A(2)%E7%AC%AC%E4%B8%80%E6%AC%A1%E8%B0%83%E7%94%A8%E6%8C%87%E9%92%88%E5%AF%B9%E8%B1%A1%E7%9A%84%20next%20%E6%96%B9%E6%B3%95%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%B0%86%E6%8C%87%E9%92%88%E6%8C%87%E5%90%91%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E7%9A%84%20%E7%AC%AC%E4%B8%80%E4%B8%AA%E6%88%90%E5%91%98%E3%80%82%0A(3)%E7%AC%AC%E4%BA%8C%E6%AC%A1%E8%B0%83%E7%94%A8%E6%8C%87%E9%92%88%E5%AF%B9%E8%B1%A1%E7%9A%84%20next%20%E6%96%B9%E6%B3%95%EF%BC%8C%E6%8C%87%E9%92%88%E5%B0%B1%E6%8C%87%E5%90%91%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E7%9A%84%E7%AC%AC%E4%BA%8C%20%E4%B8%AA%E6%88%90%E5%91%98%E3%80%82%0A(4)%E4%B8%8D%E6%96%AD%E8%B0%83%E7%94%A8%E6%8C%87%E9%92%88%E5%AF%B9%E8%B1%A1%E7%9A%84%20next%20%E6%96%B9%E6%B3%95%EF%BC%8C%E7%9B%B4%E5%88%B0%E5%AE%83%E6%8C%87%E5%90%91%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E7%9A%84%E7%BB%93%E6%9D%9F%E4%BD%8D%20%E7%BD%AE%E3%80%82%0A%E6%AF%8F%E4%B8%80%E6%AC%A1%E8%B0%83%E7%94%A8%20next%20%E6%96%B9%E6%B3%95%EF%BC%8C%E9%83%BD%E4%BC%9A%E8%BF%94%E5%9B%9E%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E7%9A%84%E5%BD%93%E5%89%8D%E6%88%90%E5%91%98%E7%9A%84%E4%BF%A1%E6%81%AF%E3%80%82%E5%85%B7%E4%BD%93%E6%9D%A5%20%E8%AF%B4%EF%BC%8C%E5%B0%B1%E6%98%AF%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%E5%8C%85%E5%90%AB%20value%20%E5%92%8C%20done%20%E4%B8%A4%E4%B8%AA%E5%B1%9E%E6%80%A7%E7%9A%84%E5%AF%B9%E8%B1%A1%E3%80%82%E5%85%B6%0A%E4%B8%AD%EF%BC%8C%20value%20%E5%B1%9E%E6%80%A7%E6%98%AF%E5%BD%93%E5%89%8D%E6%88%90%E5%91%98%E7%9A%84%E5%80%BC%EF%BC%8C%20done%20%E5%B1%9E%E6%80%A7%E6%98%AF%E4%B8%80%E4%B8%AA%E5%B8%83%E5%B0%94%E5%80%BC%EF%BC%8C%E8%A1%A8%E7%A4%BA%E9%81%8D%20%E5%8E%86%E6%98%AF%E5%90%A6%E7%BB%93%E6%9D%9F%E3%80%82%0A%60%60%60js%0Avar%20it%20%3D%20makeIterator(%5B'a'%2C%20'b'%5D)%3B%0Ait.next()%20%2F%2F%20%7B%20value%3A%20%22a%22%2C%20done%3A%20false%20%7D%0Ait.next()%20%2F%2F%20%7B%20value%3A%20%22b%22%2C%20done%3A%20false%20%7D%0Ait.next()%20%2F%2F%20%7B%20value%3A%20undefined%2C%20done%3A%20true%20%7D%0Afunction%20makeIterator(array)%20%7B%0A%20%20var%20nextIndex%20%3D%200%3B%0A%20%20return%20%7B%0A%20%20%20%20next%3A%20function()%20%7B%0A%20%20%20%20%20%20return%20nextIndex%20%3C%20array.length%20%3F%0A%20%20%20%20%20%20%20%20%7Bvalue%3A%20array%5BnextIndex%2B%2B%5D%2C%20done%3A%20false%7D%20%3A%0A%20%20%20%20%20%20%20%20%7Bvalue%3A%20undefined%2C%20done%3A%20true%7D%3B%0A%20%20%20%20%7D%0A%7D%3B%20%7D%0A%60%60%60%0A%0A%E5%A6%82%E6%9E%9C%E4%BD%BF%E7%94%A8%20TypeScript%20%E7%9A%84%E5%86%99%E6%B3%95%EF%BC%8C%E9%81%8D%E5%8E%86%E5%99%A8%E6%8E%A5%E5%8F%A3(Iterable)%E3%80%81%E6%8C%87%E9%92%88%E5%AF%B9%E8%B1%A1%20(Iterator)%E5%92%8C%20next%20%E6%96%B9%E6%B3%95%E8%BF%94%E5%9B%9E%E5%80%BC%E7%9A%84%E8%A7%84%E6%A0%BC%E5%8F%AF%E4%BB%A5%E6%8F%8F%E8%BF%B0%E5%A6%82%E4%B8%8B%E3%80%82%0A%60%60%60ts%0Ainterface%20Iterable%20%7B%0A%20%20%5BSymbol.iterator%5D()%20%3A%20Iterator%2C%0A%7D%0Ainterface%20Iterator%20%7B%0A%20%20next(value%3F%3A%20any)%20%3A%20IterationResult%2C%0A%7D%0Ainterface%20IterationResult%20%7B%0A%20%20value%3A%20any%2C%0A%20%20done%3A%20boolean%2C%0A%7D%0A%60%60%60%0A%0A%E5%BD%93%E4%BD%BF%E7%94%A8%20for...of%20%E5%BE%AA%E7%8E%AF%E9%81%8D%E5%8E%86%E6%9F%90%E7%A7%8D%20%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E6%97%B6%EF%BC%8C%E8%AF%A5%E5%BE%AA%E7%8E%AF%E4%BC%9A%E8%87%AA%E5%8A%A8%E5%8E%BB%E5%AF%BB%E6%89%BE%20Iterator%20%E6%8E%A5%E5%8F%A3%E3%80%82%0A%E4%B8%80%E7%A7%8D%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%8F%AA%E8%A6%81%E9%83%A8%E7%BD%B2%E4%BA%86%20Iterator%20%E6%8E%A5%E5%8F%A3%EF%BC%8C%E6%88%91%E4%BB%AC%E5%B0%B1%E7%A7%B0%E8%BF%99%E7%A7%8D%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E6%98%AF%E2%80%9D%E5%8F%AF%E9%81%8D%20%E5%8E%86%E7%9A%84%E2%80%9C(iterable)%E3%80%82%0AES6%20%E8%A7%84%E5%AE%9A%EF%BC%8C%E9%BB%98%E8%AE%A4%E7%9A%84%20Iterator%20%E6%8E%A5%E5%8F%A3%E9%83%A8%E7%BD%B2%E5%9C%A8%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E7%9A%84%20Symbol.iterator%20%E5%B1%9E%20%E6%80%A7%EF%BC%8C%E6%88%96%E8%80%85%E8%AF%B4%EF%BC%8C%E4%B8%80%E4%B8%AA%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%8F%AA%E8%A6%81%E5%85%B7%E6%9C%89%20Symbol.iterator%20%E5%B1%9E%E6%80%A7%EF%BC%8C%E5%B0%B1%E5%8F%AF%E4%BB%A5%20%E8%AE%A4%E4%B8%BA%E6%98%AF%E2%80%9C%E5%8F%AF%E9%81%8D%E5%8E%86%E7%9A%84%E2%80%9D(iterable)%0A%0A%0A%E5%8E%9F%E7%94%9F%E5%85%B7%E5%A4%87%20Iterator%20%E6%8E%A5%E5%8F%A3%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%A6%82%E4%B8%8B%E3%80%82%0A***Array%0AMap%0ASet%0AString%0ATypedArray%0A%E5%87%BD%E6%95%B0%E7%9A%84%20arguments%20%E5%AF%B9%E8%B1%A1%20NodeList%20%E5%AF%B9%E8%B1%A1***%0A%0A%E5%AF%B9%E4%BA%8E%E7%B1%BB%E4%BC%BC%E6%95%B0%E7%BB%84%E7%9A%84%E5%AF%B9%E8%B1%A1(%E5%AD%98%E5%9C%A8%E6%95%B0%E5%80%BC%E9%94%AE%E5%90%8D%E5%92%8C%20length%20%E5%B1%9E%E6%80%A7)%EF%BC%8C%E9%83%A8%E7%BD%B2%20Iterator%20%E6%8E%A5%E5%8F%A3%EF%BC%8C%E6%9C%89%E4%B8%80%E4%B8%AA%E7%AE%80%E4%BE%BF%E6%96%B9%E6%B3%95%EF%BC%8C%E5%B0%B1%E6%98%AF%20Symbol.iterator%20%E6%96%B9%E6%B3%95%E7%9B%B4%E6%8E%A5%E5%BC%95%E7%94%A8%E6%95%B0%E7%BB%84%E7%9A%84%20Iterator%20%E6%8E%A5%E5%8F%A3%E3%80%82%0A%0A%23%23%23%23%20%E8%B0%83%E7%94%A8%20Iterator%20%E6%8E%A5%E5%8F%A3%E7%9A%84%E5%9C%BA%E5%90%88%0A(1)%E8%A7%A3%E6%9E%84%E8%B5%8B%E5%80%BC%0A%E5%AF%B9%E6%95%B0%E7%BB%84%E5%92%8C%20Set%20%E7%BB%93%E6%9E%84%E8%BF%9B%E8%A1%8C%E8%A7%A3%E6%9E%84%E8%B5%8B%E5%80%BC%E6%97%B6%EF%BC%8C%E4%BC%9A%E9%BB%98%E8%AE%A4%E8%B0%83%E7%94%A8%20Symbol.iterator%20%E6%96%B9%E6%B3%95%E3%80%82%0A(2)%E6%89%A9%E5%B1%95%E8%BF%90%E7%AE%97%E7%AC%A6%0A%E6%89%A9%E5%B1%95%E8%BF%90%E7%AE%97%E7%AC%A6(...)%E4%B9%9F%E4%BC%9A%E8%B0%83%E7%94%A8%E9%BB%98%E8%AE%A4%E7%9A%84%20Iterator%20%E6%8E%A5%E5%8F%A3%E3%80%82%0A%E5%8F%AA%E8%A6%81%E6%9F%90%E4%B8%AA%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E9%83%A8%E7%BD%B2%E4%BA%86%20Iterator%20%E6%8E%A5%E5%8F%A3%EF%BC%8C%E5%B0%B1%20%E5%8F%AF%E4%BB%A5%E5%AF%B9%E5%AE%83%E4%BD%BF%E7%94%A8%E6%89%A9%E5%B1%95%E8%BF%90%E7%AE%97%E7%AC%A6%EF%BC%8C%E5%B0%86%E5%85%B6%E8%BD%AC%E4%B8%BA%E6%95%B0%E7%BB%84%E3%80%82%0A(3)yield*%0Ayield*%20%E5%90%8E%E9%9D%A2%E8%B7%9F%E7%9A%84%E6%98%AF%E4%B8%80%E4%B8%AA%E5%8F%AF%E9%81%8D%E5%8E%86%E7%9A%84%E7%BB%93%E6%9E%84%EF%BC%8C%E5%AE%83%E4%BC%9A%E8%B0%83%E7%94%A8%E8%AF%A5%E7%BB%93%E6%9E%84%E7%9A%84%E9%81%8D%E5%8E%86%E5%99%A8%E6%8E%A5%E5%8F%A3%E3%80%82%0A(4)%E5%85%B6%E4%BB%96%E5%9C%BA%E5%90%88%20%E7%94%B1%E4%BA%8E%E6%95%B0%E7%BB%84%E7%9A%84%E9%81%8D%E5%8E%86%E4%BC%9A%E8%B0%83%E7%94%A8%E9%81%8D%E5%8E%86%E5%99%A8%E6%8E%A5%E5%8F%A3%EF%BC%8C%E6%89%80%E4%BB%A5%E4%BB%BB%E4%BD%95%E6%8E%A5%E5%8F%97%E6%95%B0%E7%BB%84%E4%BD%9C%E4%B8%BA%E5%8F%82%E6%95%B0%E7%9A%84%E5%9C%BA%0A%E5%90%88%EF%BC%8C%E5%85%B6%E5%AE%9E%E9%83%BD%E8%B0%83%E7%94%A8%E4%BA%86%E9%81%8D%E5%8E%86%E5%99%A8%E6%8E%A5%E5%8F%A3%E3%80%82%0A%0A%23%23%23%23%20%E9%81%8D%E5%8E%86%E5%99%A8%E5%AF%B9%E8%B1%A1%E7%9A%84return()%EF%BC%8Cthrow()%0A%E9%81%8D%E5%8E%86%E5%99%A8%E5%AF%B9%E8%B1%A1%E9%99%A4%E4%BA%86%E5%85%B7%E6%9C%89%20next%20%E6%96%B9%E6%B3%95%EF%BC%8C%E8%BF%98%E5%8F%AF%E4%BB%A5%E5%85%B7%E6%9C%89%20return%20%E6%96%B9%E6%B3%95%0A%E5%92%8C%20throw%20%E6%96%B9%E6%B3%95%E3%80%82%E5%A6%82%E6%9E%9C%E4%BD%A0%E8%87%AA%E5%B7%B1%E5%86%99%E9%81%8D%E5%8E%86%E5%99%A8%E5%AF%B9%E8%B1%A1%E7%94%9F%E6%88%90%E5%87%BD%E6%95%B0%EF%BC%8C%E9%82%A3%E4%B9%88%20next%20%E6%96%B9%E6%B3%95%20%E6%98%AF%E5%BF%85%E9%A1%BB%E9%83%A8%E7%BD%B2%E7%9A%84%EF%BC%8C%20return%20%E6%96%B9%E6%B3%95%E5%92%8C%20throw%20%E6%96%B9%E6%B3%95%E6%98%AF%E5%90%A6%E9%83%A8%E7%BD%B2%E6%98%AF%E5%8F%AF%E9%80%89%E7%9A%84%E3%80%82%0A%0Areturn%20%E6%96%B9%E6%B3%95%E7%9A%84%E4%BD%BF%E7%94%A8%E5%9C%BA%E5%90%88%E6%98%AF%EF%BC%8C%E5%A6%82%E6%9E%9C%20for...of%20%E5%BE%AA%E7%8E%AF%E6%8F%90%E5%89%8D%E9%80%80%E5%87%BA(%E9%80%9A%E5%B8%B8%E6%98%AF%E5%9B%A0%20%E4%B8%BA%E5%87%BA%E9%94%99%EF%BC%8C%E6%88%96%E8%80%85%E6%9C%89%20break%20%E8%AF%AD%E5%8F%A5%E6%88%96%20continue%20%E8%AF%AD%E5%8F%A5)%EF%BC%8C%E5%B0%B1%E4%BC%9A%E8%B0%83%E7%94%A8%20return%20%E6%96%B9%E6%B3%95%E3%80%82%0Athrow%20%E6%96%B9%E6%B3%95%E4%B8%BB%E8%A6%81%E6%98%AF%E9%85%8D%E5%90%88%20Generator%20%E5%87%BD%E6%95%B0%E4%BD%BF%E7%94%A8%E3%80%82%0A%0A%23%23%23%23%20for...of%E5%BE%AA%E7%8E%AF%0A%0AJavaScript%20%E5%8E%9F%E6%9C%89%E7%9A%84%20for...in%20%E5%BE%AA%E7%8E%AF%EF%BC%8C%E5%8F%AA%E8%83%BD%E8%8E%B7%E5%BE%97%E5%AF%B9%E8%B1%A1%E7%9A%84%E9%94%AE%E5%90%8D%EF%BC%8C%E4%B8%8D%E8%83%BD%E7%9B%B4%E6%8E%A5%E8%8E%B7%20%E5%8F%96%E9%94%AE%E5%80%BC%E3%80%82ES6%20%E6%8F%90%E4%BE%9B%20for...of%20%E5%BE%AA%E7%8E%AF%EF%BC%8C%E5%85%81%E8%AE%B8%E9%81%8D%E5%8E%86%E8%8E%B7%E5%BE%97%E9%94%AE%E5%80%BC%E3%80%82%0Afor...of%20%E5%BE%AA%E7%8E%AF%E8%B0%83%E7%94%A8%E9%81%8D%E5%8E%86%E5%99%A8%E6%8E%A5%E5%8F%A3%EF%BC%8C%E6%95%B0%E7%BB%84%E7%9A%84%E9%81%8D%E5%8E%86%E5%99%A8%E6%8E%A5%E5%8F%A3%E5%8F%AA%E8%BF%94%E5%9B%9E%E5%85%B7%E6%9C%89%E6%95%B0%E5%AD%97%E7%B4%A2%20%E5%BC%95%E7%9A%84%E5%B1%9E%E6%80%A7%E3%80%82%E8%BF%99%E4%B8%80%E7%82%B9%E8%B7%9F%20for...in%20%E5%BE%AA%E7%8E%AF%E4%B9%9F%E4%B8%8D%E4%B8%80%E6%A0%B7%E3%80%82%0A%0A%20for...of%20%E5%BE%AA%E7%8E%AF%E8%BF%98%E6%9C%89%E4%B8%80%E4%B8%AA%E7%89%B9%E7%82%B9%EF%BC%8C%E5%B0%B1%E6%98%AF%E4%BC%9A%E6%AD%A3%E7%A1%AE%E8%AF%86%E5%88%AB32%E4%BD%8D%20UTF-16%20%E5%AD%97%E7%AC%A6%E3%80%82%0A%20%0A%23%23%23%23%20%20%E4%B8%8E%E5%85%B6%E4%BB%96%E9%81%8D%E5%8E%86%E8%AF%AD%E6%B3%95%E7%9A%84%E6%AF%94%E8%BE%83%0A%0A%E5%8E%9F%E5%A7%8Bfor%E5%BE%AA%E7%8E%AF%EF%BC%9A%E5%AF%B9%E4%BA%8E%E6%95%B0%E7%BB%84%E6%95%88%E7%8E%87%E9%AB%98%EF%BC%8C%E4%BD%86%E5%86%99%E6%B3%95%E6%AF%94%E8%BE%83%E9%BA%BB%E7%83%A6%E3%80%82%0AforEach%EF%BC%9A%E5%AF%B9%E4%BA%8E%E6%95%B0%E7%BB%84%E6%95%88%E7%8E%87%E9%AB%98%EF%BC%8C%E5%86%99%E6%B3%95%E6%96%B9%E4%BE%BF%EF%BC%8C%E4%BD%86%E6%98%AF%E4%B8%8D%E5%85%81%E8%AE%B8%E4%B8%AD%E9%80%94%E9%80%80%E5%87%BA%E3%80%82%0Afor..of%EF%BC%9A%E5%AF%B9%E4%BA%8E%E6%95%B0%E7%BB%84%E6%95%88%E7%8E%87%E9%AB%98%EF%BC%8C%E5%86%99%E6%B3%95%E6%96%B9%E4%BE%BF%EF%BC%8C%E5%85%81%E8%AE%B8%E4%B8%AD%E9%80%94%E9%80%80%E5%87%BA%E3%80%82%0Afor...in%EF%BC%9A%E5%BE%AA%E7%8E%AF%E5%8F%AF%E4%BB%A5%E9%81%8D%E5%8E%86%E6%95%B0%E7%BB%84%E7%9A%84%E9%94%AE%E5%90%8D%E3%80%82%0A%20%20%20%20%E7%BC%BA%E7%82%B9%EF%BC%9A%0A%20%20%20%201%E3%80%81%E6%95%B0%E7%BB%84%E7%9A%84%E9%94%AE%E5%90%8D%E6%98%AF%E6%95%B0%E5%AD%97%EF%BC%8C%E4%BD%86%E6%98%AF%20for...in%20%E5%BE%AA%E7%8E%AF%E6%98%AF%E4%BB%A5%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%BD%9C%E4%B8%BA%E9%94%AE%20%E5%90%8D%E2%80%9C0%E2%80%9D%E3%80%81%E2%80%9C1%E2%80%9D%E3%80%81%E2%80%9C2%E2%80%9D%E7%AD%89%E7%AD%89%E3%80%82%0A%20%20%20%202%E3%80%81for...in%20%E5%BE%AA%E7%8E%AF%E4%B8%8D%E4%BB%85%E9%81%8D%E5%8E%86%E6%95%B0%E5%AD%97%E9%94%AE%E5%90%8D%EF%BC%8C%E8%BF%98%E4%BC%9A%E9%81%8D%E5%8E%86%E6%89%8B%E5%8A%A8%E6%B7%BB%E5%8A%A0%E7%9A%84%E5%85%B6%E4%BB%96%E9%94%AE%EF%BC%8C%20%E7%94%9A%E8%87%B3%E5%8C%85%E6%8B%AC%E5%8E%9F%E5%9E%8B%E9%93%BE%E4%B8%8A%E7%9A%84%E9%94%AE%E3%80%82%0A%20%20%20%203%E3%80%81%E6%9F%90%E4%BA%9B%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%20for...in%20%E5%BE%AA%E7%8E%AF%E4%BC%9A%E4%BB%A5%E4%BB%BB%E6%84%8F%E9%A1%BA%E5%BA%8F%E9%81%8D%E5%8E%86%E9%94%AE%E5%90%8D%E3%80%82%0A%E6%80%BB%E4%B9%8B%EF%BC%8C%E5%BE%AA%E7%8E%AF%E4%B8%BB%E8%A6%81%E6%98%AF%E4%B8%BA%E9%81%8D%E5%8E%86%E5%AF%B9%E8%B1%A1%E8%80%8C%E8%AE%BE%E8%AE%A1%E7%9A%84%EF%BC%8C%E4%B8%8D%E9%80%82%E7%94%A8%E4%BA%8E%E9%81%8D%E5%8E%86%E6%95%B0%E7%BB%84%E3%80%82%0A%0A%23%23%20Generator%20%E5%87%BD%E6%95%B0%E7%9A%84%E8%AF%AD%E6%B3%95%0A%0AGenerator%20%E5%87%BD%E6%95%B0%E6%98%AF%20ES6%20%E6%8F%90%E4%BE%9B%E7%9A%84%E4%B8%80%E7%A7%8D%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%EF%BC%8C%E5%8F%AF%E4%BB%A5%E6%8A%8A%E5%AE%83%E7%90%86%E8%A7%A3%E6%88%90%E6%98%AF%E4%B8%80%E4%B8%AA%E7%8A%B6%E6%80%81%E6%9C%BA%EF%BC%8C%E5%B0%81%E8%A3%85%E4%BA%86%E5%A4%9A%E4%B8%AA%E5%86%85%E9%83%A8%E7%8A%B6%E6%80%81%E3%80%82%0A%E6%89%A7%E8%A1%8C%20Generator%20%E5%87%BD%E6%95%B0%E4%BC%9A%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%E9%81%8D%E5%8E%86%E5%99%A8%E5%AF%B9%E8%B1%A1%EF%BC%8C%E8%BF%94%E5%9B%9E%E7%9A%84%E9%81%8D%E5%8E%86%E5%99%A8%E5%AF%B9%E8%B1%A1%EF%BC%8C%E5%8F%AF%E4%BB%A5%E4%BE%9D%E6%AC%A1%E9%81%8D%E5%8E%86%20Generator%20%E5%87%BD%E6%95%B0%E5%86%85%E9%83%A8%E7%9A%84%E6%AF%8F%E4%B8%80%E4%B8%AA%E7%8A%B6%E6%80%81%E3%80%82%0A%0A**%E7%89%B9%E5%BE%81%EF%BC%9A**%0A1%E3%80%81function%20%E5%85%B3%E9%94%AE%E5%AD%97%E4%B8%8E%E5%87%BD%E6%95%B0%E5%90%8D%E4%B9%8B%E9%97%B4%E6%9C%89%E4%B8%80%E4%B8%AA%E6%98%9F%E5%8F%B7%E3%80%82%0A2%E3%80%81%E5%87%BD%E6%95%B0%E4%BD%93%E5%86%85%E9%83%A8%E4%BD%BF%E7%94%A8%20yield%20%E8%A1%A8%E8%BE%BE%E5%BC%8F%EF%BC%8C%E5%AE%9A%E4%B9%89%E4%B8%8D%E5%90%8C%E7%9A%84%E5%86%85%E9%83%A8%E7%8A%B6%E6%80%81(%20yield%20%E5%9C%A8%E8%8B%B1%E8%AF%AD%E9%87%8C%E7%9A%84%E6%84%8F%E6%80%9D%E5%B0%B1%20%E6%98%AF%E2%80%9C%E4%BA%A7%E5%87%BA%E2%80%9D)%E3%80%82%0A%60%60%60ts%0Afunction*%20helloWorldGenerator()%20%7B%0A%20%20yield%20'hello'%3B%0A%20%20yield%20'world'%3B%0A%20%20return%20'ending'%3B%0A%7D%0Avar%20hw%20%3D%20helloWorldGenerator()%3B%0A%60%60%60%0A%E4%B8%8A%E9%9D%A2%E4%BB%A3%E7%A0%81%E5%AE%9A%E4%B9%89%E4%BA%86%E4%B8%80%E4%B8%AA%20Generator%20%E5%87%BD%E6%95%B0%20helloWorldGenerator%20%EF%BC%8C%E5%AE%83%E5%86%85%E9%83%A8%E6%9C%89%20%E4%B8%A4%E4%B8%AA%20yield%20%E8%A1%A8%E8%BE%BE%E5%BC%8F(%20hello%20%E5%92%8C%20world%20)%EF%BC%8C%E5%8D%B3%E8%AF%A5%E5%87%BD%E6%95%B0%E6%9C%89%E4%B8%89%E4%B8%AA%E7%8A%B6%E6%80%81%3A%20hello%EF%BC%8Cworld%20%E5%92%8C%20return%20%E8%AF%AD%E5%8F%A5(%E7%BB%93%E6%9D%9F%E6%89%A7%E8%A1%8C)%E3%80%82%0A%0A%E8%B0%83%E7%94%A8%20Generator%20%E5%87%BD%E6%95%B0%E5%90%8E%EF%BC%8C%E8%AF%A5%E5%87%BD%E6%95%B0%E5%B9%B6%E4%B8%8D%E6%89%A7%E8%A1%8C%EF%BC%8C%E8%80%8C%E6%98%AF%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%E9%81%8D%E5%8E%86%E5%99%A8%E5%AF%B9%E8%B1%A1(Iterator%20Object)%EF%BC%8C%E5%BF%85%E9%A1%BB%E8%B0%83%E7%94%A8%E9%81%8D%E5%8E%86%E5%99%A8%E5%AF%B9%E8%B1%A1%E7%9A%84%20next%20%E6%96%B9%E6%B3%95%EF%BC%8C%E4%BD%BF%E5%BE%97%E6%8C%87%E9%92%88%E7%A7%BB%E5%90%91%E4%B8%8B%E4%B8%80%E4%B8%AA%E7%8A%B6%E6%80%81%E3%80%82%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%EF%BC%8C%E6%AF%8F%E6%AC%A1%E8%B0%83%E7%94%A8%20next%20%E6%96%B9%E6%B3%95%EF%BC%8C%E5%86%85%E9%83%A8%E6%8C%87%E9%92%88%E5%B0%B1%E4%BB%8E%E5%87%BD%E6%95%B0%E5%A4%B4%E9%83%A8%E6%88%96%E4%B8%8A%E4%B8%80%E6%AC%A1%20%E5%81%9C%E4%B8%8B%E6%9D%A5%E7%9A%84%E5%9C%B0%E6%96%B9%E5%BC%80%E5%A7%8B%E6%89%A7%E8%A1%8C%EF%BC%8C%E7%9B%B4%E5%88%B0%E9%81%87%E5%88%B0%E4%B8%8B%E4%B8%80%E4%B8%AA%20yield%20%E8%A1%A8%E8%BE%BE%E5%BC%8F(%E6%88%96%20return%20%E8%AF%AD%E5%8F%A5)%E4%B8%BA%E6%AD%A2%E3%80%82%0A%0A**%E9%81%8D%E5%8E%86%E5%99%A8%E5%AF%B9%E8%B1%A1%E7%9A%84%20next%20%E6%96%B9%E6%B3%95%E7%9A%84%E8%BF%90%E8%A1%8C%E9%80%BB%E8%BE%91%E5%A6%82%E4%B8%8B%EF%BC%9A**%0A(1)%E9%81%87%E5%88%B0%20yield%20%E8%A1%A8%E8%BE%BE%E5%BC%8F%EF%BC%8C%E5%B0%B1%E6%9A%82%E5%81%9C%E6%89%A7%E8%A1%8C%E5%90%8E%E9%9D%A2%E7%9A%84%E6%93%8D%E4%BD%9C%EF%BC%8C%E5%B9%B6%E5%B0%86%E7%B4%A7%E8%B7%9F%0A%E5%9C%A8%20yield%20%E5%90%8E%E9%9D%A2%E7%9A%84%E9%82%A3%E4%B8%AA%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9A%84%E5%80%BC%EF%BC%8C%E4%BD%9C%E4%B8%BA%E8%BF%94%E5%9B%9E%E7%9A%84%E5%AF%B9%E8%B1%A1%E7%9A%84%20value%20%E5%B1%9E%E6%80%A7%E5%80%BC%E3%80%82%0A(2)%E4%B8%8B%E4%B8%80%E6%AC%A1%E8%B0%83%E7%94%A8%20next%20%E6%96%B9%E6%B3%95%E6%97%B6%EF%BC%8C%E5%86%8D%E7%BB%A7%E7%BB%AD%E5%BE%80%E4%B8%8B%E6%89%A7%E8%A1%8C%EF%BC%8C%E7%9B%B4%E5%88%B0%E9%81%87%E5%88%B0%E4%B8%8B%E4%B8%80%0A%E4%B8%AA%20yield%20%E8%A1%A8%E8%BE%BE%E5%BC%8F%E3%80%82%0A(3)%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E5%86%8D%E9%81%87%E5%88%B0%E6%96%B0%E7%9A%84%20yield%20%E8%A1%A8%E8%BE%BE%E5%BC%8F%EF%BC%8C%E5%B0%B1%E4%B8%80%E7%9B%B4%E8%BF%90%E8%A1%8C%E5%88%B0%E5%87%BD%E6%95%B0%E7%BB%93%E6%9D%9F%EF%BC%8C%E7%9B%B4%20%E5%88%B0%20return%20%E8%AF%AD%E5%8F%A5%E4%B8%BA%E6%AD%A2%EF%BC%8C%E5%B9%B6%E5%B0%86%20return%20%E8%AF%AD%E5%8F%A5%E5%90%8E%E9%9D%A2%E7%9A%84%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9A%84%E5%80%BC%EF%BC%8C%E4%BD%9C%E4%B8%BA%E8%BF%94%E5%9B%9E%20%E7%9A%84%E5%AF%B9%E8%B1%A1%E7%9A%84%20value%20%E5%B1%9E%E6%80%A7%E5%80%BC%E3%80%82%0A(4)%E5%A6%82%E6%9E%9C%E8%AF%A5%E5%87%BD%E6%95%B0%E6%B2%A1%E6%9C%89%20return%20%E8%AF%AD%E5%8F%A5%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9E%E7%9A%84%E5%AF%B9%E8%B1%A1%E7%9A%84%20value%20%E5%B1%9E%E6%80%A7%E5%80%BC%20%E4%B8%BA%20undefined%20%E3%80%82%0A%0A%E9%9C%80%E8%A6%81%E6%B3%A8%E6%84%8F%E7%9A%84%E6%98%AF%EF%BC%9A%0A1%E3%80%81yield%20%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%90%8E%E9%9D%A2%E7%9A%84%E8%A1%A8%E8%BE%BE%E5%BC%8F%EF%BC%8C%E5%8F%AA%E6%9C%89%E5%BD%93%E8%B0%83%E7%94%A8%20next%20%E6%96%B9%E6%B3%95%E3%80%81%E5%86%85%E9%83%A8%E6%8C%87%E9%92%88%E6%8C%87%E5%90%91%E8%AF%A5%E8%AF%AD%E5%8F%A5%E6%97%B6%E6%89%8D%E4%BC%9A%E6%89%A7%E8%A1%8C%0A2%E3%80%81yield%20%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%8F%AA%E8%83%BD%E7%94%A8%E5%9C%A8%20Generator%20%E5%87%BD%E6%95%B0%E9%87%8C%E9%9D%A2%EF%BC%8C%E7%94%A8%E5%9C%A8%E5%85%B6%E4%BB%96%20%E5%9C%B0%E6%96%B9%E9%83%BD%E4%BC%9A%E6%8A%A5%E9%94%99%0A3%E3%80%81yield%20%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%A6%82%E6%9E%9C%E7%94%A8%E5%9C%A8%E5%8F%A6%E4%B8%80%E4%B8%AA%E8%A1%A8%E8%BE%BE%E5%BC%8F%E4%B9%8B%E4%B8%AD%EF%BC%8C%E5%BF%85%E9%A1%BB%E6%94%BE%E5%9C%A8%E5%9C%86%E6%8B%AC%E5%8F%B7%E9%87%8C%20%E9%9D%A2%E3%80%82%0A%60%60%60ts%0Afunction*%20demo()%20%7B%0A%20%20console.log('Hello'%20%2B%20yield)%3B%20%2F%2F%20SyntaxError%0A%20%20console.log('Hello'%20%2B%20yield%20123)%3B%20%2F%2F%20SyntaxError%0A%20%20console.log('Hello'%20%2B%20(yield))%3B%20%2F%2F%20OK%0A%20%20console.log('Hello'%20%2B%20(yield%20123))%3B%20%2F%2F%20OK%0A%7D%0A%60%60%60%0A4%E3%80%81yield%20%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%94%A8%E4%BD%9C%E5%87%BD%E6%95%B0%E5%8F%82%E6%95%B0%E6%88%96%E6%94%BE%E5%9C%A8%E8%B5%8B%E5%80%BC%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9A%84%E5%8F%B3%E8%BE%B9%EF%BC%8C%E5%8F%AF%E4%BB%A5%E4%B8%8D%E5%8A%A0%E6%8B%AC%E5%8F%B7%E3%80%82%0A%60%60%60ts%0Afunction*%20demo()%20%7B%0A%20%20foo(yield%20'a'%2C%20yield%20'b')%3B%20%2F%2F%20OK%0A%20%20let%20input%20%3D%20yield%3B%20%2F%2F%20OK%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%20%E4%B8%8E%20Iterator%20%E6%8E%A5%E5%8F%A3%E7%9A%84%E5%85%B3%E7%B3%BB%0A%0A%E4%B8%8A%E4%B8%80%E7%AB%A0%E8%AF%B4%E8%BF%87%EF%BC%8C%E4%BB%BB%E6%84%8F%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%E7%9A%84%20Symbol.iterator%20%E6%96%B9%E6%B3%95%EF%BC%8C%E7%AD%89%E4%BA%8E%E8%AF%A5%E5%AF%B9%E8%B1%A1%E7%9A%84%0A%E9%81%8D%E5%8E%86%E5%99%A8%E7%94%9F%E6%88%90%E5%87%BD%E6%95%B0%EF%BC%8C%E8%B0%83%E7%94%A8%E8%AF%A5%E5%87%BD%E6%95%B0%E4%BC%9A%E8%BF%94%E5%9B%9E%E8%AF%A5%E5%AF%B9%E8%B1%A1%E7%9A%84%E4%B8%80%E4%B8%AA%E9%81%8D%E5%8E%86%E5%99%A8%E5%AF%B9%E8%B1%A1%E3%80%82%0A%E7%94%B1%E4%BA%8E%20Generator%20%E5%87%BD%E6%95%B0%E5%B0%B1%E6%98%AF%E9%81%8D%E5%8E%86%E5%99%A8%E7%94%9F%E6%88%90%E5%87%BD%E6%95%B0%EF%BC%8C%E5%9B%A0%E6%AD%A4%E5%8F%AF%E4%BB%A5%E6%8A%8A%20Generator%20%E8%B5%8B%E5%80%BC%E7%BB%99%E5%AF%B9%E8%B1%A1%E7%9A%84%20Symbol.iterator%20%E5%B1%9E%E6%80%A7%EF%BC%8C%E4%BB%8E%E8%80%8C%E4%BD%BF%E5%BE%97%E8%AF%A5%E5%AF%B9%E8%B1%A1%E5%85%B7%E6%9C%89%20Iterator%20%E6%8E%A5%E5%8F%A3%E3%80%82%0A%0A%0AGenerator%20%E5%87%BD%E6%95%B0%E6%89%A7%E8%A1%8C%E5%90%8E%EF%BC%8C%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%E9%81%8D%E5%8E%86%E5%99%A8%E5%AF%B9%E8%B1%A1%E3%80%82%E8%AF%A5%E5%AF%B9%E8%B1%A1%E6%9C%AC%E8%BA%AB%E4%B9%9F%E5%85%B7%20%E6%9C%89%20Symbol.iterator%20%E5%B1%9E%E6%80%A7%EF%BC%8C%E6%89%A7%E8%A1%8C%E5%90%8E%E8%BF%94%E5%9B%9E%E8%87%AA%E8%BA%AB%E3%80%82%0A%60%60%60ts%0Afunction*%20gen()%7B%0A%20%20%2F%2F%20some%20code%0A%7D%0Avar%20g%20%3D%20gen()%3B%0Ag%5BSymbol.iterator%5D()%20%3D%3D%3D%20g%0A%2F%2F%20true%0A%60%60%60%0A%0A%23%23%23%23%20next%20%E6%96%B9%E6%B3%95%E7%9A%84%E5%8F%82%E6%95%B0%0Ayield%20%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%9C%AC%E8%BA%AB%E6%B2%A1%E6%9C%89%E8%BF%94%E5%9B%9E%E5%80%BC%EF%BC%8C%E6%88%96%E8%80%85%E8%AF%B4%E6%80%BB%E6%98%AF%E8%BF%94%E5%9B%9E%20undefined%20%E3%80%82%20next%20%E6%96%B9%E6%B3%95%E5%8F%AF%E4%BB%A5%E5%B8%A6%E4%B8%80%E4%B8%AA%E5%8F%82%E6%95%B0%EF%BC%8C%E8%AF%A5%E5%8F%82%E6%95%B0%E5%B0%B1%E4%BC%9A%E8%A2%AB%E5%BD%93%E4%BD%9C%E4%B8%8A%E4%B8%80%E4%B8%AA%20yield%20%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9A%84%E8%BF%94%E5%9B%9E%E5%80%BC%E3%80%82%0A*%E6%B3%A8%E6%84%8F%EF%BC%8C%E7%94%B1%E4%BA%8E%20next%20%E6%96%B9%E6%B3%95%E7%9A%84%E5%8F%82%E6%95%B0%E8%A1%A8%E7%A4%BA%E4%B8%8A%E4%B8%80%E4%B8%AA%20yield%20%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9A%84%E8%BF%94%E5%9B%9E%E5%80%BC%EF%BC%8C%E6%89%80%20%E4%BB%A5%E5%9C%A8%E7%AC%AC%E4%B8%80%E6%AC%A1%E4%BD%BF%E7%94%A8%20next%20%E6%96%B9%E6%B3%95%E6%97%B6%EF%BC%8C%E4%BC%A0%E9%80%92%E5%8F%82%E6%95%B0%E6%98%AF%E6%97%A0%E6%95%88%E7%9A%84%E3%80%82V8%20%E5%BC%95%E6%93%8E%E7%9B%B4%E6%8E%A5%E5%BF%BD%E7%95%A5%E7%AC%AC%20%E4%B8%80%E6%AC%A1%E4%BD%BF%E7%94%A8%20next%20%E6%96%B9%E6%B3%95%E6%97%B6%E7%9A%84%E5%8F%82%E6%95%B0%EF%BC%8C%E5%8F%AA%E6%9C%89%E4%BB%8E%E7%AC%AC%E4%BA%8C%E6%AC%A1%E4%BD%BF%E7%94%A8%20next%20%E6%96%B9%E6%B3%95%E5%BC%80%E5%A7%8B%EF%BC%8C%E5%8F%82%20%E6%95%B0%E6%89%8D%E6%98%AF%E6%9C%89%E6%95%88%E7%9A%84%E3%80%82*%0A%0A%23%23%23%23%20for...of%20%E5%BE%AA%E7%8E%AF%0Afor...of%20%E5%BE%AA%E7%8E%AF%E5%8F%AF%E4%BB%A5%E8%87%AA%E5%8A%A8%E9%81%8D%E5%8E%86%20Generator%20%E5%87%BD%E6%95%B0%E6%97%B6%E7%94%9F%E6%88%90%E7%9A%84%20Iterator%20%E5%AF%B9%E8%B1%A1%EF%BC%8C%E4%B8%94%E6%AD%A4%E6%97%B6%E4%B8%8D%E5%86%8D%E9%9C%80%E8%A6%81%E8%B0%83%E7%94%A8%20next%20%E6%96%B9%E6%B3%95%E3%80%82%0A%0A*%E9%9C%80%E8%A6%81%E6%B3%A8%E6%84%8F%EF%BC%8C%E4%B8%80%E6%97%A6%20next%20%E6%96%B9%E6%B3%95%E7%9A%84%E8%BF%94%E5%9B%9E%E5%AF%B9%E8%B1%A1%E7%9A%84%20done%20%E5%B1%9E%E6%80%A7%0A%E4%B8%BA%20true%20%EF%BC%8C%20for...of%20%E5%BE%AA%E7%8E%AF%E5%B0%B1%E4%BC%9A%E4%B8%AD%E6%AD%A2%EF%BC%8C%E4%B8%94%E4%B8%8D%E5%8C%85%E5%90%AB%E8%AF%A5%E8%BF%94%E5%9B%9E%E5%AF%B9%E8%B1%A1%EF%BC%8C%E6%89%80%E4%BB%A5%E4%B8%8A%E9%9D%A2%20%E4%BB%A3%E7%A0%81%E7%9A%84%20return%20%E8%AF%AD%E5%8F%A5%E8%BF%94%E5%9B%9E%E7%9A%84%206%20%EF%BC%8C%E4%B8%8D%E5%8C%85%E6%8B%AC%E5%9C%A8%20for...of%20%E5%BE%AA%E7%8E%AF%E4%B9%8B%E4%B8%AD%E3%80%82*%0A%0A%23%23%23%23%20Generator.prototype.throw()%0AGenerator%20%E5%87%BD%E6%95%B0%E8%BF%94%E5%9B%9E%E7%9A%84%E9%81%8D%E5%8E%86%E5%99%A8%E5%AF%B9%E8%B1%A1%EF%BC%8C%E9%83%BD%E6%9C%89%E4%B8%80%E4%B8%AA%20throw%20%E6%96%B9%E6%B3%95%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%9C%A8%E5%87%BD%E6%95%B0%20%E4%BD%93%E5%A4%96%E6%8A%9B%E5%87%BA%E9%94%99%E8%AF%AF%EF%BC%8C%E7%84%B6%E5%90%8E%E5%9C%A8%20Generator%20%E5%87%BD%E6%95%B0%E4%BD%93%E5%86%85%E6%8D%95%E8%8E%B7%E3%80%82%0A%0A*%E6%B3%A8%E6%84%8F%EF%BC%8C%E4%B8%8D%E8%A6%81%E6%B7%B7%E6%B7%86%E9%81%8D%E5%8E%86%E5%99%A8%E5%AF%B9%E8%B1%A1%E7%9A%84%20throw%20%E6%96%B9%E6%B3%95%E5%92%8C%E5%85%A8%E5%B1%80%E7%9A%84%20throw%20%E5%91%BD%E4%BB%A4%E3%80%82%E4%B8%8A%E9%9D%A2%20%E4%BB%A3%E7%A0%81%E7%9A%84%E9%94%99%E8%AF%AF%EF%BC%8C%E6%98%AF%E7%94%A8%E9%81%8D%E5%8E%86%E5%99%A8%E5%AF%B9%E8%B1%A1%E7%9A%84%20throw%20%E6%96%B9%E6%B3%95%E6%8A%9B%E5%87%BA%E7%9A%84%EF%BC%8C%E8%80%8C%E4%B8%8D%E6%98%AF%E7%94%A8%20throw%20%E5%91%BD%E4%BB%A4%E6%8A%9B%E5%87%BA%E7%9A%84%E3%80%82%E5%90%8E%E8%80%85%E5%8F%AA%E8%83%BD%E8%A2%AB%E5%87%BD%E6%95%B0%E4%BD%93%E5%A4%96%E7%9A%84%20catch%20%E8%AF%AD%E5%8F%A5%E6%8D%95%E8%8E%B7%E3%80%82*%0A%0Athrow%20%E6%96%B9%E6%B3%95%E8%A2%AB%E6%8D%95%E8%8E%B7%E4%BB%A5%E5%90%8E%EF%BC%8C%E4%BC%9A%E9%99%84%E5%B8%A6%E6%89%A7%E8%A1%8C%E4%B8%8B%E4%B8%80%E6%9D%A1%20yield%20%E8%A1%A8%E8%BE%BE%E5%BC%8F%E3%80%82%E4%B9%9F%E5%B0%B1%E6%98%AF%20%E8%AF%B4%EF%BC%8C%E4%BC%9A%E9%99%84%E5%B8%A6%E6%89%A7%E8%A1%8C%E4%B8%80%E6%AC%A1%20next%20%E6%96%B9%E6%B3%95%E3%80%82%0A%60%60%60ts%0Avar%20gen%20%3D%20function*%20gen()%7B%0A%20%20try%20%7B%0A%20%20%20%20yield%20console.log('a')%3B%0A%20%20%7D%20catch%20(e)%20%7B%0A%2F%2F%20...%0A%20%20%7D%0A%20%20yield%20console.log('b')%3B%0A%20%20yield%20console.log('c')%3B%0A%7D%0Avar%20g%20%3D%20gen()%3B%0Ag.next()%20%2F%2F%20a%0Ag.throw()%20%2F%2F%20b%0Ag.next()%20%2F%2F%20c%0A%60%60%60%0A%0A%E4%B8%80%E6%97%A6%20Generator%20%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8B%E4%B8%AD%E6%8A%9B%E5%87%BA%E9%94%99%E8%AF%AF%EF%BC%8C%E4%B8%94%E6%B2%A1%E6%9C%89%E8%A2%AB%E5%86%85%E9%83%A8%E6%8D%95%E8%8E%B7%EF%BC%8C%E5%B0%B1%E4%B8%8D%E4%BC%9A%E5%86%8D%E6%89%A7%E8%A1%8C%20%E4%B8%8B%E5%8E%BB%E4%BA%86%E3%80%82%E5%A6%82%E6%9E%9C%E6%AD%A4%E5%90%8E%E8%BF%98%E8%B0%83%E7%94%A8%20next%20%E6%96%B9%E6%B3%95%EF%BC%8C%E5%B0%86%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%20value%20%E5%B1%9E%E6%80%A7%E7%AD%89%E4%BA%8E%20undefined%20%E3%80%81%20done%20%E5%B1%9E%E6%80%A7%E7%AD%89%E4%BA%8E%20true%20%E7%9A%84%E5%AF%B9%E8%B1%A1%EF%BC%8C%E5%8D%B3%20JavaScript%20%E5%BC%95%E6%93%8E%E8%AE%A4%20%E4%B8%BA%E8%BF%99%E4%B8%AA%20Generator%20%E5%B7%B2%E7%BB%8F%E8%BF%90%E8%A1%8C%E7%BB%93%E6%9D%9F%E4%BA%86%0A%0A%23%23%23%23%20Generator.prototype.return()%0AGenerator%20%E5%87%BD%E6%95%B0%E8%BF%94%E5%9B%9E%E7%9A%84%E9%81%8D%E5%8E%86%E5%99%A8%E5%AF%B9%E8%B1%A1%EF%BC%8C%E8%BF%98%E6%9C%89%E4%B8%80%E4%B8%AA%20return%20%E6%96%B9%E6%B3%95%EF%BC%8C%E5%8F%AF%E4%BB%A5%E8%BF%94%E5%9B%9E%E7%BB%99%E5%AE%9A%E7%9A%84%E5%80%BC%EF%BC%8C%E5%B9%B6%E4%B8%94%E7%BB%88%E7%BB%93%E9%81%8D%E5%8E%86%20Generator%20%E5%87%BD%E6%95%B0%E3%80%82%0A%60%60%60js%0Afunction*%20gen()%20%7B%0A%20%20yield%201%3B%0A%20%20yield%202%3B%0A%20%20yield%203%3B%0A%7D%0Avar%20g%20%3D%20gen()%3B%0Ag.next()%0Ag.return('foo')%20%2F%2F%20%7B%20value%3A%20%22foo%22%2C%20done%3A%20true%20%7D%0Ag.next()%20%20%20%20%20%20%20%20%2F%2F%20%7B%20value%3A%20undefined%2C%20done%3A%20true%20%7D%0A%60%60%60%0A%0A%E5%A6%82%E6%9E%9C%20return%20%E6%96%B9%E6%B3%95%E8%B0%83%E7%94%A8%E6%97%B6%EF%BC%8C%E4%B8%8D%E6%8F%90%E4%BE%9B%E5%8F%82%E6%95%B0%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9E%E5%80%BC%E7%9A%84%20value%20%E5%B1%9E%E6%80%A7%20%E4%B8%BA%20undefined%20%E3%80%82%0A%0A%E5%A6%82%E6%9E%9C%20Generator%20%E5%87%BD%E6%95%B0%E5%86%85%E9%83%A8%E6%9C%89%20try...finally%20%E4%BB%A3%E7%A0%81%E5%9D%97%EF%BC%8C%E9%82%A3%E4%B9%88%20return%20%E6%96%B9%E6%B3%95%20%E4%BC%9A%E6%8E%A8%E8%BF%9F%E5%88%B0%20finally%20%E4%BB%A3%E7%A0%81%E5%9D%97%E6%89%A7%E8%A1%8C%E5%AE%8C%E5%86%8D%E6%89%A7%E8%A1%8C%E3%80%82%0A%60%60%60js%0Afunction*%20numbers%20()%20%7B%0A%20%20yield%201%3B%0A%20%20try%20%7B%0Ayield%202%3B%0A%20%20%20%20yield%203%3B%0A%20%20%7D%20finally%20%7B%0Ayield%204%3B%0Ayield%205%3B%20%7D%0Ayield%206%3B%20%7D%0Avar%20g%20%3D%20numbers()%3B%0Ag.next()%20%2F%2F%20%7B%20value%3A%201%2C%20done%3A%20false%20%7D%0Ag.next()%20%2F%2F%20%7B%20value%3A%202%2C%20done%3A%20false%20%7D%0Ag.return(7)%20%2F%2F%20%7B%20value%3A%204%2C%20done%3A%20false%20%7D%0Ag.next()%20%2F%2F%20%7B%20value%3A%205%2C%20done%3A%20false%20%7D%0Ag.next()%20%2F%2F%20%7B%20value%3A%207%2C%20done%3A%20true%20%7D%0A%60%60%60%0A%0A%23%23%23%23%20yield*%20%E8%A1%A8%E8%BE%BE%E5%BC%8F%0A%E5%A6%82%E6%9E%9C%E5%9C%A8%20Generator%20%E5%87%BD%E6%95%B0%E5%86%85%E9%83%A8%EF%BC%8C%E8%B0%83%E7%94%A8%E5%8F%A6%E4%B8%80%E4%B8%AA%20Generator%20%E5%87%BD%E6%95%B0%EF%BC%8C%E9%BB%98%E8%AE%A4%E6%83%85%E5%86%B5%E4%B8%8B%E6%98%AF%E6%B2%A1%E6%9C%89%E6%95%88%E6%9E%9C%E7%9A%84%EF%BC%8C%E8%BF%99%E6%97%B6%E5%B0%B1%E9%9C%80%E8%A6%81%E7%94%A8%E5%88%B0%20yield*%20%E8%A1%A8%E8%BE%BE%E5%BC%8F%EF%BC%8C%E7%94%A8%E6%9D%A5%E5%9C%A8%E4%B8%80%E4%B8%AA%20Generator%20%E5%87%BD%E6%95%B0%E9%87%8C%E9%9D%A2%E6%89%A7%E8%A1%8C%20%E5%8F%A6%E4%B8%80%E4%B8%AAGenerator%20%E5%87%BD%E6%95%B0%E3%80%82%0A%60%60%60js%0Afunction*%20bar()%20%7B%0A%20%20yield%20'x'%3B%0A%20%20yield*%20foo()%3B%0A%20%20yield%20'y'%3B%0A%7D%0A%2F%2F%20%E7%AD%89%E5%90%8C%E4%BA%8E%20function*%20bar()%20%7B%0A%20%20yield%20'x'%3B%0A%20%20yield%20'a'%3B%0A%20%20yield%20'b'%3B%0A%20%20yield%20'y'%3B%0A%7D%0A%2F%2F%20%E7%AD%89%E5%90%8C%E4%BA%8E%20function*%20bar()%20%7B%0A%20%20yield%20'x'%3B%0A%20%20for%20(let%20v%20of%20foo())%20%7B%0Ayield%20v%3B%20%7D%0Ayield%20'y'%3B%20%7D%0Afor%20(let%20v%20of%20bar())%7B%0A%20%20console.log(v)%3B%0A%7D%0A%2F%2F%20%22x%22%0A%2F%2F%20%22a%22%0A%2F%2F%20%22b%22%0A%2F%2F%20%22y%22%0A%60%60%60%0A%0A*yield*%20%E5%90%8E%E9%9D%A2%E7%9A%84Generator%E5%87%BD%E6%95%B0(%E6%B2%A1%E6%9C%89%20return%20%E8%AF%AD%E5%8F%A5%20%E6%97%B6)%EF%BC%8C%E4%B8%8D%E8%BF%87%E6%98%AF%20for...of%20%E7%9A%84%E4%B8%80%E7%A7%8D%E7%AE%80%E5%86%99%E5%BD%A2%E5%BC%8F%EF%BC%8C%E5%AE%8C%E5%85%A8%E5%8F%AF%E4%BB%A5%E7%94%A8%E5%90%8E%E8%80%85%E6%9B%BF%E4%BB%A3%E5%89%8D%E8%80%85%E3%80%82%20%E5%8F%8D%E4%B9%8B%EF%BC%8C%E5%9C%A8%E6%9C%89%20return%20%E8%AF%AD%E5%8F%A5%E6%97%B6%EF%BC%8C%E5%88%99%E9%9C%80%E8%A6%81%E7%94%A8%20var%20value%20%3D%20yield*%20iterator%20%E7%9A%84%E5%BD%A2%E5%BC%8F%E8%8E%B7%E5%8F%96%20return%20%E8%AF%AD%E5%8F%A5%E7%9A%84%E5%80%BC%E3%80%82*%0A%0A%E4%BB%BB%E4%BD%95%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%8F%AA%E8%A6%81%E6%9C%89%20Iterator%20%E6%8E%A5%E5%8F%A3%EF%BC%8C%E5%B0%B1%E5%8F%AF%E4%BB%A5%E8%A2%AB%20yield*%20%E9%81%8D%E5%8E%86%E3%80%82%0A%0A%23%23%23%23%20%E4%BD%9C%E4%B8%BA%E5%AF%B9%E8%B1%A1%E5%B1%9E%E6%80%A7%E7%9A%84Generator%E5%87%BD%E6%95%B0%0A%E5%A6%82%E6%9E%9C%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%B1%9E%E6%80%A7%E6%98%AF%20Generator%20%E5%87%BD%E6%95%B0%EF%BC%8C%E5%8F%AF%E4%BB%A5%E7%AE%80%E5%86%99%E6%88%90%E4%B8%8B%E9%9D%A2%E7%9A%84%E5%BD%A2%E5%BC%8F%E3%80%82%0A%60%60%60js%0Alet%20obj%20%3D%20%7B%0A%20%20*%20myGeneratorMethod()%20%7B%0A%C2%B7%C2%B7%C2%B7%20%7D%0A%7D%3B%0A%0A%2F%2F%E7%AD%89%E5%90%8C%E4%BA%8E%0Alet%20obj%20%3D%20%7B%0A%20%20myGeneratorMethod%3A%20function*%20()%20%7B%0A%2F%2F%20%C2%B7%C2%B7%C2%B7%0A%7D%20%7D%3B%0A%60%60%60%0A%0A%23%23%23%23%20Generator%20%E5%87%BD%E6%95%B0%E7%9A%84%20this%0AGenerator%20%E5%87%BD%E6%95%B0%E6%80%BB%E6%98%AF%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%E9%81%8D%E5%8E%86%E5%99%A8%EF%BC%8CES6%20%E8%A7%84%E5%AE%9A%E8%BF%99%E4%B8%AA%E9%81%8D%E5%8E%86%E5%99%A8%E6%98%AF%20Generator%E5%87%BD%E6%95%B0%E7%9A%84%E5%AE%9E%E4%BE%8B%EF%BC%8C%E4%B9%9F%E7%BB%A7%E6%89%BF%E4%BA%86%20Generator%20%E5%87%BD%E6%95%B0%E7%9A%84%20prototype%20%E5%AF%B9%E8%B1%A1%E4%B8%8A%E7%9A%84%E6%96%B9%E6%B3%95%E3%80%82%0A%60%60%60js%0Afunction*%20g()%20%7B%7D%0Ag.prototype.hello%20%3D%20function%20()%20%7B%0A%20%20return%20'hi!'%3B%0A%7D%3B%0Alet%20obj%20%3D%20g()%3B%0Aobj%20instanceof%20g%20%2F%2F%20true%0Aobj.hello()%20%2F%2F%20'hi!'%0A%60%60%60%0A%E4%B8%8A%E9%9D%A2%E4%BB%A3%E7%A0%81%E8%A1%A8%E6%98%8E%EF%BC%8CGenerator%20%E5%87%BD%E6%95%B0%20g%20%E8%BF%94%E5%9B%9E%E7%9A%84%E9%81%8D%E5%8E%86%E5%99%A8%20obj%20%EF%BC%8C%E6%98%AF%20g%20%E7%9A%84%E5%AE%9E%E4%BE%8B%EF%BC%8C%20%E8%80%8C%E4%B8%94%E7%BB%A7%E6%89%BF%E4%BA%86%20g.prototype%20%E3%80%82%E4%BD%86%E6%98%AF%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%8A%8A%20g%20%E5%BD%93%E4%BD%9C%E6%99%AE%E9%80%9A%E7%9A%84%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%EF%BC%8C%E5%B9%B6%E4%B8%8D%E4%BC%9A%E7%94%9F%E6%95%88%EF%BC%8C%E5%9B%A0%E4%B8%BA%20g%20%E8%BF%94%E5%9B%9E%E7%9A%84%E6%80%BB%E6%98%AF%E9%81%8D%E5%8E%86%E5%99%A8%E5%AF%B9%E8%B1%A1%EF%BC%8C%E8%80%8C%E4%B8%8D%E6%98%AF%20this%20%E5%AF%B9%E8%B1%A1%E3%80%82%0A%60%60%60js%0Afunction*%20g()%20%7B%0A%20%20this.a%20%3D%2011%3B%0A%7D%0Alet%20obj%20%3D%20g()%3B%0Aobj.a%20%2F%2F%20undefined%0A%60%60%60%0A%E4%B8%8A%E9%9D%A2%E4%BB%A3%E7%A0%81%E4%B8%AD%EF%BC%8CGenerator%E5%87%BD%E6%95%B0%20g%20%E5%9C%A8%20this%20%E5%AF%B9%E8%B1%A1%E4%B8%8A%E9%9D%A2%E6%B7%BB%E5%8A%A0%E4%BA%86%E4%B8%80%E4%B8%AA%E5%B1%9E%E6%80%A7%20a%20%EF%BC%8C%20%E4%BD%86%E6%98%AF%20obj%20%E5%AF%B9%E8%B1%A1%E6%8B%BF%E4%B8%8D%E5%88%B0%E8%BF%99%E4%B8%AA%E5%B1%9E%E6%80%A7%E3%80%82%0A*Generator%E5%87%BD%E6%95%B0%E4%B9%9F%E4%B8%8D%E8%83%BD%E8%B7%9F%20new%20%E5%91%BD%E4%BB%A4%E4%B8%80%E8%B5%B7%E7%94%A8%EF%BC%8C%E4%BC%9A%E6%8A%A5%E9%94%99%E3%80%82*%0A%0A%23%23%23%23%20Generator%20%E4%B8%8E%E7%8A%B6%E6%80%81%E6%9C%BA%0AGenerator%20%E6%98%AF%E5%AE%9E%E7%8E%B0%E7%8A%B6%E6%80%81%E6%9C%BA%E7%9A%84%E6%9C%80%E4%BD%B3%E7%BB%93%E6%9E%84%E3%80%82%0A%60%60%60js%0Avar%20ticking%20%3D%20true%3B%0Avar%20clock%20%3D%20function()%20%7B%0A%20%20if%20(ticking)%0A%20%20%20%20console.log('Tick!')%3B%0Aelse%0A%20%20%20%20console.log('Tock!')%3B%0A%20%20ticking%20%3D%20!ticking%3B%0A%7D%0A%0A%2F%2F%E5%B0%91%E4%BA%86%E7%94%A8%E6%9D%A5%E4%BF%9D%E5%AD%98%E7%8A%B6%E6%80%81%E7%9A%84%20%E5%A4%96%E9%83%A8%E5%8F%98%E9%87%8F%20ticking%E3%80%82%20%E6%9B%B4%E7%AE%80%E6%B4%81%EF%BC%8C%E6%9B%B4%E5%AE%89%E5%85%A8%0Avar%20clock%20%3D%20function*%20()%20%7B%0A%20%20while%20(true)%20%7B%0A%20%20%20%20console.log('Tick!')%3B%0A%20%20%20%20yield%3B%0A%20%20%20%20console.log('Tock!')%3B%0A%20%20%20%20yield%3B%0A%7D%20%7D%3B%0A%60%60%60%0A%0A%23%23%23%23%20Generator%E4%B8%8E%E5%8D%8F%E7%A8%8B%0A%E5%8D%8F%E7%A8%8B(coroutine)%E6%98%AF%E4%B8%80%E7%A7%8D%E7%A8%8B%E5%BA%8F%E8%BF%90%E8%A1%8C%E7%9A%84%E6%96%B9%E5%BC%8F%EF%BC%8C%E5%8F%AF%E4%BB%A5%E7%90%86%E8%A7%A3%E6%88%90%E2%80%9C%E5%8D%8F%E4%BD%9C%E7%9A%84%E7%BA%BF%20%E7%A8%8B%E2%80%9D%E6%88%96%E2%80%9C%E5%8D%8F%E4%BD%9C%E7%9A%84%E5%87%BD%E6%95%B0%E2%80%9D%E3%80%82%E5%8D%8F%E7%A8%8B%E6%97%A2%E5%8F%AF%E4%BB%A5%E7%94%A8%E5%8D%95%E7%BA%BF%E7%A8%8B%E5%AE%9E%E7%8E%B0%EF%BC%8C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E7%94%A8%E5%A4%9A%E7%BA%BF%E7%A8%8B%E5%AE%9E%E7%8E%B0%E3%80%82%20%E5%89%8D%E8%80%85%E6%98%AF%E4%B8%80%E7%A7%8D%E7%89%B9%E6%AE%8A%E7%9A%84%E5%AD%90%E4%BE%8B%E7%A8%8B%EF%BC%8C%E5%90%8E%E8%80%85%E6%98%AF%E4%B8%80%E7%A7%8D%E7%89%B9%E6%AE%8A%E7%9A%84%E7%BA%BF%E7%A8%8B%E3%80%82%0A%0A%23%23%23%23%23%20(1)%E5%8D%8F%E7%A8%8B%E4%B8%8E%E5%AD%90%E4%BE%8B%E7%A8%8B%E7%9A%84%E5%B7%AE%E5%BC%82%0A%E4%BC%A0%E7%BB%9F%E7%9A%84%E2%80%9C%E5%AD%90%E4%BE%8B%E7%A8%8B%E2%80%9D(subroutine)%E9%87%87%E7%94%A8%E5%A0%86%E6%A0%88%E5%BC%8F%E2%80%9C%E5%90%8E%E8%BF%9B%E5%85%88%E5%87%BA%E2%80%9D%E7%9A%84%E6%89%A7%E8%A1%8C%E6%96%B9%E5%BC%8F%EF%BC%8C%E5%8F%AA%E6%9C%89%20%E5%BD%93%E8%B0%83%E7%94%A8%E7%9A%84%E5%AD%90%E5%87%BD%E6%95%B0%E5%AE%8C%E5%85%A8%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%AF%95%EF%BC%8C%E6%89%8D%E4%BC%9A%E7%BB%93%E6%9D%9F%E6%89%A7%E8%A1%8C%E7%88%B6%E5%87%BD%E6%95%B0%E3%80%82%E5%8D%8F%E7%A8%8B%E4%B8%8E%E5%85%B6%E4%B8%8D%E5%90%8C%EF%BC%8C%20%E5%A4%9A%E4%B8%AA%E7%BA%BF%E7%A8%8B(%E5%8D%95%E7%BA%BF%E7%A8%8B%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%E5%8D%B3%E5%A4%9A%E4%B8%AA%E5%87%BD%E6%95%B0)%E5%8F%AF%E4%BB%A5%E5%B9%B6%E8%A1%8C%E6%89%A7%E8%A1%8C%EF%BC%8C%E4%BD%86%E6%98%AF%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AA%20%E7%BA%BF%E7%A8%8B(%E6%88%96%E5%87%BD%E6%95%B0)%E5%A4%84%E4%BA%8E%E6%AD%A3%E5%9C%A8%E8%BF%90%E8%A1%8C%E7%9A%84%E7%8A%B6%E6%80%81%EF%BC%8C%E5%85%B6%E4%BB%96%E7%BA%BF%E7%A8%8B(%E6%88%96%E5%87%BD%E6%95%B0)%E9%83%BD%E5%A4%84%E4%BA%8E%E6%9A%82%E5%81%9C%20%E6%80%81(suspended)%EF%BC%8C%E7%BA%BF%E7%A8%8B(%E6%88%96%E5%87%BD%E6%95%B0)%E4%B9%8B%E9%97%B4%E5%8F%AF%E4%BB%A5%E4%BA%A4%E6%8D%A2%E6%89%A7%E8%A1%8C%E6%9D%83%E3%80%82%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%EF%BC%8C%E4%B8%80%20%E4%B8%AA%E7%BA%BF%E7%A8%8B(%E6%88%96%E5%87%BD%E6%95%B0)%E6%89%A7%E8%A1%8C%E5%88%B0%E4%B8%80%E5%8D%8A%EF%BC%8C%E5%8F%AF%E4%BB%A5%E6%9A%82%E5%81%9C%E6%89%A7%E8%A1%8C%EF%BC%8C%E5%B0%86%E6%89%A7%E8%A1%8C%E6%9D%83%E4%BA%A4%E7%BB%99%E5%8F%A6%E4%B8%80%E4%B8%AA%E7%BA%BF%20%E7%A8%8B(%E6%88%96%E5%87%BD%E6%95%B0)%EF%BC%8C%E7%AD%89%E5%88%B0%E7%A8%8D%E5%90%8E%E6%94%B6%E5%9B%9E%E6%89%A7%E8%A1%8C%E6%9D%83%E7%9A%84%E6%97%B6%E5%80%99%EF%BC%8C%E5%86%8D%E6%81%A2%E5%A4%8D%E6%89%A7%E8%A1%8C%E3%80%82%E8%BF%99%E7%A7%8D%E5%8F%AF%E4%BB%A5%E5%B9%B6%20%E8%A1%8C%E6%89%A7%E8%A1%8C%E3%80%81%E4%BA%A4%E6%8D%A2%E6%89%A7%E8%A1%8C%E6%9D%83%E7%9A%84%E7%BA%BF%E7%A8%8B(%E6%88%96%E5%87%BD%E6%95%B0)%EF%BC%8C%E5%B0%B1%E7%A7%B0%E4%B8%BA%E5%8D%8F%E7%A8%8B%E3%80%82%0A%E4%BB%8E%E5%AE%9E%E7%8E%B0%E4%B8%8A%E7%9C%8B%EF%BC%8C%E5%9C%A8%E5%86%85%E5%AD%98%E4%B8%AD%EF%BC%8C%E5%AD%90%E4%BE%8B%E7%A8%8B%E5%8F%AA%E4%BD%BF%E7%94%A8%E4%B8%80%E4%B8%AA%E6%A0%88(stack)%EF%BC%8C%E8%80%8C%E5%8D%8F%E7%A8%8B%E6%98%AF%E5%90%8C%E6%97%B6%20%E5%AD%98%E5%9C%A8%E5%A4%9A%E4%B8%AA%E6%A0%88%EF%BC%8C%E4%BD%86%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AA%E6%A0%88%E6%98%AF%E5%9C%A8%E8%BF%90%E8%A1%8C%E7%8A%B6%E6%80%81%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%EF%BC%8C%E5%8D%8F%E7%A8%8B%E6%98%AF%E4%BB%A5%E5%A4%9A%E5%8D%A0%E7%94%A8%20%E5%86%85%E5%AD%98%E4%B8%BA%E4%BB%A3%E4%BB%B7%EF%BC%8C%E5%AE%9E%E7%8E%B0%E5%A4%9A%E4%BB%BB%E5%8A%A1%E7%9A%84%E5%B9%B6%E8%A1%8C%E3%80%82%0A%0A%23%23%23%23%23%20(2)%E5%8D%8F%E7%A8%8B%E4%B8%8E%E6%99%AE%E9%80%9A%E7%BA%BF%E7%A8%8B%E7%9A%84%E5%B7%AE%E5%BC%82%0A%E5%8D%8F%E7%A8%8B%E4%B8%8E%E6%99%AE%E9%80%9A%E7%9A%84%E7%BA%BF%E7%A8%8B%E5%BE%88%E7%9B%B8%E4%BC%BC%EF%BC%8C%E9%83%BD%E6%9C%89%E8%87%AA%E5%B7%B1%E7%9A%84%E6%89%A7%E8%A1%8C%E4%B8%8A%E4%B8%8B%E6%96%87%E3%80%81%E5%8F%AF%E4%BB%A5%E5%88%86%E4%BA%AB%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F%E3%80%82%0A%E4%B8%8D%E5%90%8C%EF%BC%9A%0A1%E3%80%81%E5%90%8C%E4%B8%80%E6%97%B6%E9%97%B4%E5%8F%AF%E4%BB%A5%E6%9C%89%E5%A4%9A%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%A4%84%E4%BA%8E%E8%BF%90%E8%A1%8C%E7%8A%B6%E6%80%81%EF%BC%8C%E4%BD%86%E6%98%AF%E8%BF%90%E8%A1%8C%E7%9A%84%E5%8D%8F%E7%A8%8B%0A%E5%8F%AA%E8%83%BD%E6%9C%89%E4%B8%80%E4%B8%AA%EF%BC%8C%E5%85%B6%E4%BB%96%E5%8D%8F%E7%A8%8B%E9%83%BD%E5%A4%84%E4%BA%8E%E6%9A%82%E5%81%9C%E7%8A%B6%E6%80%81%E3%80%82%0A2%E3%80%81%E6%99%AE%E9%80%9A%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%98%AF%E6%8A%A2%E5%85%88%E5%BC%8F%E7%9A%84%EF%BC%8C%E5%88%B0%E5%BA%95%E5%93%AA%E4%B8%AA%E7%BA%BF%E7%A8%8B%E4%BC%98%E5%85%88%E5%BE%97%E5%88%B0%E8%B5%84%E6%BA%90%EF%BC%8C%E5%BF%85%E9%A1%BB%E7%94%B1%E8%BF%90%E8%A1%8C%E7%8E%AF%E5%A2%83%E5%86%B3%E5%AE%9A%EF%BC%8C%E4%BD%86%E6%98%AF%E5%8D%8F%E7%A8%8B%E6%98%AF%E5%90%88%E4%BD%9C%E5%BC%8F%E7%9A%84%EF%BC%8C%E6%89%A7%E8%A1%8C%E6%9D%83%E7%94%B1%E5%8D%8F%E7%A8%8B%E8%87%AA%E5%B7%B1%E5%88%86%E9%85%8D%E3%80%82%0A%0A%E7%94%B1%E4%BA%8E%20JavaScript%20%E6%98%AF%E5%8D%95%E7%BA%BF%E7%A8%8B%E8%AF%AD%E8%A8%80%EF%BC%8C%E5%8F%AA%E8%83%BD%E4%BF%9D%E6%8C%81%E4%B8%80%E4%B8%AA%E8%B0%83%E7%94%A8%E6%A0%88%E3%80%82%E5%BC%95%E5%85%A5%E5%8D%8F%E7%A8%8B%E4%BB%A5%E5%90%8E%EF%BC%8C%20%E6%AF%8F%E4%B8%AA%E4%BB%BB%E5%8A%A1%E5%8F%AF%E4%BB%A5%E4%BF%9D%E6%8C%81%E8%87%AA%E5%B7%B1%E7%9A%84%E8%B0%83%E7%94%A8%E6%A0%88%E3%80%82%E8%BF%99%E6%A0%B7%E5%81%9A%E7%9A%84%E6%9C%80%E5%A4%A7%E5%A5%BD%E5%A4%84%EF%BC%8C%E5%B0%B1%E6%98%AF%E6%8A%9B%E5%87%BA%E9%94%99%E8%AF%AF%E7%9A%84%20%E6%97%B6%E5%80%99%EF%BC%8C%E5%8F%AF%E4%BB%A5%E6%89%BE%E5%88%B0%E5%8E%9F%E5%A7%8B%E7%9A%84%E8%B0%83%E7%94%A8%E6%A0%88%E3%80%82%0A%0AGenerator%20%E5%87%BD%E6%95%B0%E6%98%AF%20ES6%20%E5%AF%B9%E5%8D%8F%E7%A8%8B%E7%9A%84%E5%AE%9E%E7%8E%B0%EF%BC%8C%E4%BD%86%E5%B1%9E%E4%BA%8E%E4%B8%8D%E5%AE%8C%E5%85%A8%E5%AE%9E%E7%8E%B0%E3%80%82Generator%20%E5%87%BD%20%E6%95%B0%E8%A2%AB%E7%A7%B0%E4%B8%BA%E2%80%9C%E5%8D%8A%E5%8D%8F%E7%A8%8B%E2%80%9D(semi-coroutine)%EF%BC%8C%E6%84%8F%E6%80%9D%E6%98%AF%E5%8F%AA%E6%9C%89%20Generator%20%E5%87%BD%E6%95%B0%E7%9A%84%E8%B0%83%E7%94%A8%20%E8%80%85%EF%BC%8C%E6%89%8D%E8%83%BD%E5%B0%86%E7%A8%8B%E5%BA%8F%E7%9A%84%E6%89%A7%E8%A1%8C%E6%9D%83%E8%BF%98%E7%BB%99%20Generator%20%E5%87%BD%E6%95%B0%E3%80%82%E5%A6%82%E6%9E%9C%E6%98%AF%E5%AE%8C%E5%85%A8%E6%89%A7%E8%A1%8C%E7%9A%84%E5%8D%8F%E7%A8%8B%EF%BC%8C%20%E4%BB%BB%E4%BD%95%E5%87%BD%E6%95%B0%E9%83%BD%E5%8F%AF%E4%BB%A5%E8%AE%A9%E6%9A%82%E5%81%9C%E7%9A%84%E5%8D%8F%E7%A8%8B%E7%BB%A7%E7%BB%AD%E6%89%A7%E8%A1%8C%E3%80%82%0A%0A%23%23%23%23%20%E5%BA%94%E7%94%A8%0AGenerator%20%E5%8F%AF%E4%BB%A5%E6%9A%82%E5%81%9C%E5%87%BD%E6%95%B0%E6%89%A7%E8%A1%8C%EF%BC%8C%E8%BF%94%E5%9B%9E%E4%BB%BB%E6%84%8F%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9A%84%E5%80%BC%E3%80%82%E8%BF%99%E7%A7%8D%E7%89%B9%E7%82%B9%E4%BD%BF%E5%BE%97%20Generator%20%E6%9C%89%E5%A4%9A%E7%A7%8D%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF%E3%80%82%0A%0A%23%23%23%23%23%20(1)%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%E7%9A%84%E5%90%8C%E6%AD%A5%E5%8C%96%E8%A1%A8%E8%BE%BE%0A%60%60%60js%0Afunction*%20loadUI()%20%7B%0A%20%20showLoadingScreen()%3B%0A%20%20yield%20loadUIDataAsynchronously()%3B%0A%20%20hideLoadingScreen()%3B%0A%7D%0Avar%20loader%20%3D%20loadUI()%3B%20%2F%2F%20%E5%8A%A0%E8%BD%BDUI%20loader.next()%0A%2F%2F%20%E5%8D%B8%E8%BD%BDUI%0Aloader.next()%0A%60%60%60%0A%0A%23%23%23%23%23%20(2)%E6%8E%A7%E5%88%B6%E6%B5%81%E7%AE%A1%E7%90%86%0A%E6%9C%89%E4%B8%80%E4%B8%AA%E5%A4%9A%E6%AD%A5%E6%93%8D%E4%BD%9C%E9%9D%9E%E5%B8%B8%E8%80%97%E6%97%B6%EF%BC%8C%E9%87%87%E7%94%A8%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%EF%BC%8C%E5%8F%AF%E8%83%BD%E4%BC%9A%E5%86%99%E6%88%90%E4%B8%8B%E9%9D%A2%E8%BF%99%E6%A0%B7%0A%60%60%60js%0A%2F%2F%E6%99%AE%E9%80%9A%E5%AE%9E%E7%8E%B0%0Astep1(function%20(value1)%20%7B%0A%20%20step2(value1%2C%20function(value2)%20%7B%0A%20%20%20%20step3(value2%2C%20function(value3)%20%7B%0A%20%20%20%20%20%20step4(value3%2C%20function(value4)%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%20Do%20something%20with%20value4%0A%7D)%3B%20%7D)%3B%0A%7D)%3B%20%7D)%3B%0A%0A%2F%2FPromise%20%E5%AE%9E%E7%8E%B0%0APromise.resolve(step1)%0A%20%20.then(step2)%0A%20%20.then(step3)%0A%20%20.then(step4)%0A%20%20.then(function%20(value4)%20%7B%0A%20%20%20%20%2F%2F%20Do%20something%20with%20value4%0A%20%20%7D%2C%20function%20(error)%20%7B%0A%20%20%20%20%2F%2F%20Handle%20any%20error%20from%20step1%20through%20step4%0A%7D)%20.done()%3B%0A%0A%2F%2FGenerator%20%E5%AE%9E%E7%8E%B0%0Afunction*%20longRunningTask(value1)%20%7B%0A%20%20try%20%7B%0A%20%20%20%20var%20value2%20%3D%20yield%20step1(value1)%3B%0A%20%20%20%20var%20value3%20%3D%20yield%20step2(value2)%3B%0A%20%20%20%20var%20value4%20%3D%20yield%20step3(value3)%3B%0A%20%20%20%20var%20value5%20%3D%20yield%20step4(value4)%3B%0A%20%20%20%20%2F%2F%20Do%20something%20with%20value4%0A%20%20%7D%20catch%20(e)%20%7B%0A%20%20%20%20%2F%2F%20Handle%20any%20error%20from%20step1%20through%20step4%0A%7D%20%7D%0A%60%60%60%0A*%E4%B8%8A%E9%9D%A2%E8%BF%99%E7%A7%8D%E5%81%9A%E6%B3%95%EF%BC%8C%E5%8F%AA%E9%80%82%E5%90%88%E5%90%8C%E6%AD%A5%E6%93%8D%E4%BD%9C%EF%BC%8C%E5%8D%B3%E6%89%80%E6%9C%89%E7%9A%84%20task%20%E9%83%BD%E5%BF%85%E9%A1%BB%E6%98%AF%E5%90%8C%E6%AD%A5%20%E7%9A%84%EF%BC%8C%E4%B8%8D%E8%83%BD%E6%9C%89%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%E3%80%82%E5%9B%A0%E4%B8%BA%E8%BF%99%E9%87%8C%E7%9A%84%E4%BB%A3%E7%A0%81%E4%B8%80%E5%BE%97%E5%88%B0%E8%BF%94%E5%9B%9E%E5%80%BC%EF%BC%8C%E5%B0%B1%E7%BB%A7%E7%BB%AD%E5%BE%80%E4%B8%8B%E6%89%A7%20%E8%A1%8C%EF%BC%8C%E6%B2%A1%E6%9C%89%E5%88%A4%E6%96%AD%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%E4%BD%95%E6%97%B6%E5%AE%8C%E6%88%90%E3%80%82*%0A%0A%23%23%23%23%23%20(3)%E9%83%A8%E7%BD%B2%20Iterator%20%E6%8E%A5%E5%8F%A3%0A%60%60%60js%0Afunction*%20iterEntries(obj)%20%7B%0A%20%20let%20keys%20%3D%20Object.keys(obj)%3B%0A%20%20for%20(let%20i%3D0%3B%20i%20%3C%20keys.length%3B%20i%2B%2B)%20%7B%0A%20%20%20%20let%20key%20%3D%20keys%5Bi%5D%3B%0A%20%20%20%20yield%20%5Bkey%2C%20obj%5Bkey%5D%5D%3B%0A%20%20%7D%0A%7D%0Alet%20myObj%20%3D%20%7B%20foo%3A%203%2C%20bar%3A%207%20%7D%3B%0Afor%20(let%20%5Bkey%2C%20value%5D%20of%20iterEntries(myObj))%20%7B%0A%20%20console.log(key%2C%20value)%3B%0A%7D%0A%2F%2F%20foo%203%0A%2F%2F%20bar%207%0A%60%60%60%0A%0A%23%23%23%23%23%20(4)%E4%BD%9C%E4%B8%BA%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%0AGenerator%20%E5%8F%AF%E4%BB%A5%E7%9C%8B%E4%BD%9C%E6%98%AF%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%EF%BC%8C%E6%9B%B4%E7%A1%AE%E5%88%87%E5%9C%B0%E8%AF%B4%EF%BC%8C%E5%8F%AF%E4%BB%A5%E7%9C%8B%E4%BD%9C%E6%98%AF%E4%B8%80%E4%B8%AA%E6%95%B0%E7%BB%84%E7%BB%93%20%E6%9E%84%EF%BC%8C%E5%9B%A0%E4%B8%BA%20Generator%20%E5%87%BD%E6%95%B0%E5%8F%AF%E4%BB%A5%E8%BF%94%E5%9B%9E%E4%B8%80%E7%B3%BB%E5%88%97%E7%9A%84%E5%80%BC%EF%BC%8C%E8%BF%99%E6%84%8F%E5%91%B3%E7%9D%80%E5%AE%83%E5%8F%AF%E4%BB%A5%E5%AF%B9%E4%BB%BB%E6%84%8F%E8%A1%A8%E8%BE%BE%E5%BC%8F%EF%BC%8C%E6%8F%90%E4%BE%9B%E7%B1%BB%E4%BC%BC%E6%95%B0%E7%BB%84%E7%9A%84%E6%8E%A5%E5%8F%A3%E3%80%82%0A%60%60%60js%0Afunction%20*doStuff()%20%7B%0A%20%20yield%20fs.readFile.bind(null%2C%20'hello.txt')%3B%0A%20%20yield%20fs.readFile.bind(null%2C%20'world.txt')%3B%0A%20%20yield%20fs.readFile.bind(null%2C%20'and-such.txt')%3B%0A%7D%0A%60%60%60%0A%E4%B8%8A%E9%9D%A2%E4%BB%A3%E7%A0%81%E5%B0%B1%E6%98%AF%E4%BE%9D%E6%AC%A1%E8%BF%94%E5%9B%9E%E4%B8%89%E4%B8%AA%E5%87%BD%E6%95%B0%EF%BC%8C%E4%BD%86%E6%98%AF%E7%94%B1%E4%BA%8E%E4%BD%BF%E7%94%A8%E4%BA%86%20Generator%20%E5%87%BD%E6%95%B0%EF%BC%8C%E5%AF%BC%E8%87%B4%20%E5%8F%AF%E4%BB%A5%E5%83%8F%E5%A4%84%E7%90%86%E6%95%B0%E7%BB%84%E9%82%A3%E6%A0%B7%EF%BC%8C%E5%A4%84%E7%90%86%E8%BF%99%E4%B8%89%E4%B8%AA%E8%BF%94%E5%9B%9E%E7%9A%84%E5%87%BD%E6%95%B0%E3%80%82%0A%60%60%60js%0Afor%20(task%20of%20doStuff())%20%7B%0A%2F%2F%20task%E6%98%AF%E4%B8%80%E4%B8%AA%E5%87%BD%E6%95%B0%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%83%8F%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E9%82%A3%E6%A0%B7%E4%BD%BF%E7%94%A8%E5%AE%83%0A%7D%0A%60%60%60%0A%0A%23%23%20Generator%20%E5%87%BD%E6%95%B0%E7%9A%84%E5%BC%82%E6%AD%A5%E5%BA%94%E7%94%A8%0A%0AES6%20%E8%AF%9E%E7%94%9F%E4%BB%A5%E5%89%8D%EF%BC%8C%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E5%A4%A7%E6%A6%82%E6%9C%89%E4%B8%8B%E9%9D%A2%E5%9B%9B%E7%A7%8D%E3%80%82%0A1.%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%0A2.%E4%BA%8B%E4%BB%B6%E7%9B%91%E5%90%AC%0A3.%E5%8F%91%E5%B8%83%2F%E8%AE%A2%E9%98%85%0A4.Promise%20%E5%AF%B9%E8%B1%A1%0A%0A%0A%E6%89%80%E8%B0%93%E2%80%9D%E5%BC%82%E6%AD%A5%E2%80%9D%EF%BC%8C%E7%AE%80%E5%8D%95%E8%AF%B4%E5%B0%B1%E6%98%AF%E4%B8%80%E4%B8%AA%E4%BB%BB%E5%8A%A1%E4%B8%8D%E6%98%AF%E8%BF%9E%E7%BB%AD%E5%AE%8C%E6%88%90%E7%9A%84%EF%BC%8C%E5%8F%AF%E4%BB%A5%E7%90%86%E8%A7%A3%E6%88%90%E8%AF%A5%E4%BB%BB%E5%8A%A1%20%E8%A2%AB%E4%BA%BA%E4%B8%BA%E5%88%86%E6%88%90%E4%B8%A4%E6%AE%B5%EF%BC%8C%E5%85%88%E6%89%A7%E8%A1%8C%E7%AC%AC%E4%B8%80%E6%AE%B5%EF%BC%8C%E7%84%B6%E5%90%8E%E8%BD%AC%E8%80%8C%E6%89%A7%E8%A1%8C%E5%85%B6%E4%BB%96%E4%BB%BB%E5%8A%A1%EF%BC%8C%E7%AD%89%E5%81%9A%E5%A5%BD%E4%BA%86%E5%87%86%20%E5%A4%87%EF%BC%8C%E5%86%8D%E5%9B%9E%E8%BF%87%E5%A4%B4%E6%89%A7%E8%A1%8C%E7%AC%AC%E4%BA%8C%E6%AE%B5%E3%80%82%0A%0A%23%23%23%23%20%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%0A%60%60%60js%0Afs.readFile('%2Fetc%2Fpasswd'%2C%20'utf-8'%2C%20function%20(err%2C%20data)%0A%7B%0A%20%20if%20(err)%20throw%20err%3B%0A%20%20console.log(data)%3B%0A%7D)%3B%0A%60%60%60%0A%0A%E4%B8%80%E4%B8%AA%E6%9C%89%E8%B6%A3%E7%9A%84%E9%97%AE%E9%A2%98%E6%98%AF%EF%BC%8C%E4%B8%BA%E4%BB%80%E4%B9%88Node%E7%BA%A6%E5%AE%9A%EF%BC%8C%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%8F%82%E6%95%B0%EF%BC%8C%E5%BF%85%E9%A1%BB%E6%98%AF%E9%94%99%E8%AF%AF%E5%AF%B9%E8%B1%A1err(%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E9%94%99%E8%AF%AF%EF%BC%8C%E8%AF%A5%E5%8F%82%E6%95%B0%E5%B0%B1%E6%98%AFnull)%3F%E5%8E%9F%E5%9B%A0%E6%98%AF%E6%89%A7%E8%A1%8C%E5%88%86%E6%88%90%E4%B8%A4%E6%AE%B5%EF%BC%8C%E7%AC%AC%E4%B8%80%E6%AE%B5%E6%89%A7%E8%A1%8C%E5%AE%8C%E4%BB%A5%E5%90%8E%EF%BC%8C%E4%BB%BB%E5%8A%A1%E6%89%80%E5%9C%A8%E7%9A%84%E4%B8%8A%E4%B8%8B%E6%96%87%E7%8E%AF%E5%A2%83%E5%B0%B1%E5%B7%B2%E7%BB%8F%E7%BB%93%E6%9D%9F%E4%BA%86%E3%80%82%E5%9C%A8%E8%BF%99%E4%BB%A5%E5%90%8E%E6%8A%9B%E5%87%BA%E7%9A%84%E9%94%99%E8%AF%AF%EF%BC%8C%E5%8E%9F%E6%9D%A5%E7%9A%84%E4%B8%8A%E4%B8%8B%E6%96%87%E7%8E%AF%E5%A2%83%E5%B7%B2%E7%BB%8F%E6%97%A0%E6%B3%95%E6%8D%95%E6%8D%89%EF%BC%8C%E5%8F%AA%E8%83%BD%E5%BD%93%E4%BD%9C%E5%8F%82%E6%95%B0%EF%BC%8C%E4%BC%A0%E5%85%A5%E7%AC%AC%E4%BA%8C%E6%AE%B5%E3%80%82%0A%0A%23%23%23%23%20Promise%0A%0A%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E6%9C%AC%E8%BA%AB%E5%B9%B6%E6%B2%A1%E6%9C%89%E9%97%AE%E9%A2%98%EF%BC%8C%E5%AE%83%E7%9A%84%E9%97%AE%E9%A2%98%E5%87%BA%E7%8E%B0%E5%9C%A8%E5%A4%9A%E4%B8%AA%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E5%B5%8C%E5%A5%97%E3%80%82%E5%81%87%E5%AE%9A%E8%AF%BB%20%E5%8F%96%20A%20%E6%96%87%E4%BB%B6%E4%B9%8B%E5%90%8E%EF%BC%8C%E5%86%8D%E8%AF%BB%E5%8F%96%20B%20%E6%96%87%E4%BB%B6%EF%BC%8C%E4%BB%A3%E7%A0%81%E5%A6%82%E4%B8%8B%E3%80%82%0A%60%60%60js%0Afs.readFile(fileA%2C%20'utf-8'%2C%20function%20(err%2C%20data)%20%7B%0A%20%20fs.readFile(fileB%2C%20'utf-8'%2C%20function%20(err%2C%20data)%20%7B%0A%2F%2F%20...%0A%7D)%3B%20%7D)%3B%0A%60%60%60%0A%E5%A6%82%E6%9E%9C%E4%BE%9D%E6%AC%A1%E8%AF%BB%E5%8F%96%E4%B8%A4%E4%B8%AA%E4%BB%A5%E4%B8%8A%E7%9A%84%E6%96%87%E4%BB%B6%EF%BC%8C%E5%B0%B1%E4%BC%9A%E5%87%BA%E7%8E%B0%E5%A4%9A%E9%87%8D%E5%B5%8C%E5%A5%97%E3%80%82%E4%BB%A3%E7%A0%81%E5%9B%A0%E4%B8%BA%E5%A4%9A%E4%B8%AA%20%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%E5%BD%A2%E6%88%90%E4%BA%86%E5%BC%BA%E8%80%A6%E5%90%88%EF%BC%8C%E5%8F%AA%E8%A6%81%E6%9C%89%E4%B8%80%E4%B8%AA%E6%93%8D%E4%BD%9C%E9%9C%80%E8%A6%81%E4%BF%AE%E6%94%B9%EF%BC%8C%E5%AE%83%E7%9A%84%E4%B8%8A%E5%B1%82%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E5%92%8C%E4%B8%8B%E5%B1%82%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%EF%BC%8C%E5%8F%AF%E8%83%BD%E9%83%BD%E8%A6%81%E8%B7%9F%E7%9D%80%E4%BF%AE%E6%94%B9%E3%80%82%E8%BF%99%E7%A7%8D%E6%83%85%E5%86%B5%E5%B0%B1%E7%A7%B0%E4%B8%BA%E2%80%9D%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E5%9C%B0%20%E7%8B%B1%E2%80%9D(callback%20hell)%E3%80%82%0A%0APromise%20%E5%AF%B9%E8%B1%A1%E5%B0%B1%E6%98%AF%E4%B8%BA%E4%BA%86%E8%A7%A3%E5%86%B3%E8%BF%99%E4%B8%AA%E9%97%AE%E9%A2%98%E8%80%8C%E6%8F%90%E5%87%BA%E7%9A%84%E3%80%82%E5%AE%83%E4%B8%8D%E6%98%AF%E6%96%B0%E7%9A%84%E8%AF%AD%E6%B3%95%E5%8A%9F%E8%83%BD%EF%BC%8C%E8%80%8C%20%E6%98%AF%E4%B8%80%E7%A7%8D%E6%96%B0%E7%9A%84%E5%86%99%E6%B3%95%EF%BC%8C%E5%85%81%E8%AE%B8%E5%B0%86%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E7%9A%84%E5%B5%8C%E5%A5%97%EF%BC%8C%E6%94%B9%E6%88%90%E9%93%BE%E5%BC%8F%E8%B0%83%E7%94%A8%E3%80%82%0A%60%60%60js%0Avar%20readFile%20%3D%20require('fs-readfile-promise')%3B%0AreadFile(fileA)%0A.then(function%20(data)%20%7B%0A%20%20console.log(data.toString())%3B%0A%7D)%0A.then(function%20()%20%7B%0A%20%20return%20readFile(fileB)%3B%0A%7D)%0A.then(function%20(data)%20%7B%0A%20%20console.log(data.toString())%3B%0A%7D)%0A.catch(function%20(err)%20%7B%0A%20%20console.log(err)%3B%0A%7D)%3B%0A%60%60%60%0A*Promise%20%E7%9A%84%E6%9C%80%E5%A4%A7%E9%97%AE%E9%A2%98%E6%98%AF%E4%BB%A3%E7%A0%81%E5%86%97%E4%BD%99%EF%BC%8C%E5%8E%9F%E6%9D%A5%E7%9A%84%E4%BB%BB%E5%8A%A1%E8%A2%AB%20Promise%20%E5%8C%85%E8%A3%85%E4%BA%86%E4%B8%80%E4%B8%8B%EF%BC%8C%E4%B8%8D%20%E7%AE%A1%E4%BB%80%E4%B9%88%E6%93%8D%E4%BD%9C%EF%BC%8C%E4%B8%80%E7%9C%BC%E7%9C%8B%E5%8E%BB%E9%83%BD%E6%98%AF%E4%B8%80%E5%A0%86%20then%20%EF%BC%8C%E5%8E%9F%E6%9D%A5%E7%9A%84%E8%AF%AD%E4%B9%89%E5%8F%98%E5%BE%97%E5%BE%88%E4%B8%8D%E6%B8%85%E6%A5%9A%E3%80%82*%0A%0A%23%23%23%23%20Generator%20%E5%87%BD%E6%95%B0%0A%0A%23%23%23%23%23%20%E5%8D%8F%E7%A8%8B%0A%E5%8D%8F%E7%A8%8B%E6%9C%89%E7%82%B9%E5%83%8F%E5%87%BD%E6%95%B0%EF%BC%8C%E5%8F%88%E6%9C%89%E7%82%B9%E5%83%8F%E7%BA%BF%E7%A8%8B%E3%80%82%E5%AE%83%E7%9A%84%E8%BF%90%E8%A1%8C%E6%B5%81%E7%A8%8B%E5%A4%A7%E8%87%B4%E5%A6%82%E4%B8%8B%E3%80%82%0A%E7%AC%AC%E4%B8%80%E6%AD%A5%EF%BC%8C%E5%8D%8F%E7%A8%8BA%E5%BC%80%E5%A7%8B%E6%89%A7%E8%A1%8C%E3%80%82%0A%E7%AC%AC%E4%BA%8C%E6%AD%A5%EF%BC%8C%E5%8D%8F%E7%A8%8BA%E6%89%A7%E8%A1%8C%E5%88%B0%E4%B8%80%E5%8D%8A%EF%BC%8C%E8%BF%9B%E5%85%A5%E6%9A%82%E5%81%9C%EF%BC%8C%E6%89%A7%E8%A1%8C%E6%9D%83%E8%BD%AC%E7%A7%BB%E5%88%B0%E5%8D%8F%E7%A8%8BB%E3%80%82%20%0A%E7%AC%AC%E4%B8%89%E6%AD%A5%EF%BC%8C(%E4%B8%80%E6%AE%B5%E6%97%B6%E9%97%B4%E5%90%8E)%E5%8D%8F%E7%A8%8BB%E4%BA%A4%E8%BF%98%E6%89%A7%E8%A1%8C%E6%9D%83%E3%80%82%0A%E7%AC%AC%E5%9B%9B%E6%AD%A5%EF%BC%8C%E5%8D%8F%E7%A8%8BA%E6%81%A2%E5%A4%8D%E6%89%A7%E8%A1%8C%E3%80%82%0A%0AGenerator%20%E5%87%BD%E6%95%B0%E6%98%AF%E5%8D%8F%E7%A8%8B%E5%9C%A8%20ES6%20%E7%9A%84%E5%AE%9E%E7%8E%B0%EF%BC%8C%E6%9C%80%E5%A4%A7%E7%89%B9%E7%82%B9%E5%B0%B1%E6%98%AF%E5%8F%AF%E4%BB%A5%E4%BA%A4%E5%87%BA%E5%87%BD%E6%95%B0%E7%9A%84%E6%89%A7%E8%A1%8C%E6%9D%83(%E5%8D%B3%E6%9A%82%E5%81%9C%E6%89%A7%E8%A1%8C)%E3%80%82%0A%0A%23%23%23%23%20Thunk%20%E5%87%BD%E6%95%B0%0A%0AThunk%20%E5%87%BD%E6%95%B0%E6%98%AF%E8%87%AA%E5%8A%A8%E6%89%A7%E8%A1%8C%20Generator%20%E5%87%BD%E6%95%B0%E7%9A%84%E4%B8%80%E7%A7%8D%E6%96%B9%E6%B3%95%0A%0A%E7%BC%96%E8%AF%91%E5%99%A8%E7%9A%84%E2%80%9C%E4%BC%A0%E5%90%8D%E8%B0%83%E7%94%A8%E2%80%9D%E5%AE%9E%E7%8E%B0%EF%BC%8C%E5%BE%80%E5%BE%80%E6%98%AF%E5%B0%86%E5%8F%82%E6%95%B0%E6%94%BE%E5%88%B0%E4%B8%80%E4%B8%AA%E4%B8%B4%E6%97%B6%E5%87%BD%E6%95%B0%E4%B9%8B%E4%B8%AD%EF%BC%8C%E5%86%8D%E5%B0%86%E8%BF%99%E4%B8%AA%E4%B8%B4%E6%97%B6%E5%87%BD%E6%95%B0%E4%BC%A0%E5%85%A5%E5%87%BD%E6%95%B0%E4%BD%93%E3%80%82%E8%BF%99%E4%B8%AA%E4%B8%B4%E6%97%B6%E5%87%BD%E6%95%B0%E5%B0%B1%E5%8F%AB%E5%81%9A%20Thunk%20%E5%87%BD%E6%95%B0%E3%80%82%0A%60%60%60js%0Afunction%20f(m)%20%7B%0A%20%20return%20m%20*%202%3B%0A%7D%0Af(x%20%2B%205)%3B%20%2F%2F%20%E7%AD%89%E5%90%8C%E4%BA%8E%0Avar%20thunk%20%3D%20function%20()%20%7B%0A%20%20return%20x%20%2B%205%3B%0A%7D%3B%0Afunction%20f(thunk)%20%7B%0A%20%20return%20thunk()%20*%202%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%20JavaScript%20%E8%AF%AD%E8%A8%80%E7%9A%84%20Thunk%20%E5%87%BD%E6%95%B0%0AJavaScript%20%E8%AF%AD%E8%A8%80%E6%98%AF%E4%BC%A0%E5%80%BC%E8%B0%83%E7%94%A8%EF%BC%8C%E5%AE%83%E7%9A%84%20Thunk%20%E5%87%BD%E6%95%B0%E5%90%AB%E4%B9%89%E6%9C%89%E6%89%80%E4%B8%8D%E5%90%8C%E3%80%82%E5%9C%A8%20JavaScript%20%E8%AF%AD%E8%A8%80%E4%B8%AD%EF%BC%8CThunk%20%E5%87%BD%E6%95%B0%E6%9B%BF%E6%8D%A2%E7%9A%84%E4%B8%8D%E6%98%AF%E8%A1%A8%E8%BE%BE%E5%BC%8F%EF%BC%8C%E8%80%8C%E6%98%AF%E5%A4%9A%E5%8F%82%E6%95%B0%E5%87%BD%E6%95%B0%EF%BC%8C%E5%B0%86%20%E5%85%B6%E6%9B%BF%E6%8D%A2%E6%88%90%E4%B8%80%E4%B8%AA%E5%8F%AA%E6%8E%A5%E5%8F%97%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E4%BD%9C%E4%B8%BA%E5%8F%82%E6%95%B0%E7%9A%84%E5%8D%95%E5%8F%82%E6%95%B0%E5%87%BD%E6%95%B0%E3%80%82%0A%60%60%60js%0A%2F%2F%20%E6%AD%A3%E5%B8%B8%E7%89%88%E6%9C%AC%E7%9A%84readFile(%E5%A4%9A%E5%8F%82%E6%95%B0%E7%89%88%E6%9C%AC)%0Afs.readFile(fileName%2C%20callback)%3B%0A%2F%2F%20Thunk%E7%89%88%E6%9C%AC%E7%9A%84readFile(%E5%8D%95%E5%8F%82%E6%95%B0%E7%89%88%E6%9C%AC)%0Avar%20Thunk%20%3D%20function%20(fileName)%20%7B%0A%20%20return%20function%20(callback)%20%7B%0A%20%20%20%20return%20fs.readFile(fileName%2C%20callback)%3B%0A%20%20%7D%3B%0A%7D%3B%0Avar%20readFileThunk%20%3D%20Thunk(fileName)%3B%0AreadFileThunk(callback)%3B%0A%60%60%60%0A%0A%23%23%23%23%20Thunkify%20%E6%A8%A1%E5%9D%97%0A%E5%AE%89%E8%A3%85%3A%0A%60%60%60%0A%24%20npm%20install%20thunkify%0A%60%60%60%0A%E4%BD%BF%E7%94%A8%E6%96%B9%E5%BC%8F%3A%0A%60%60%60js%0Avar%20thunkify%20%3D%20require('thunkify')%3B%0Avar%20fs%20%3D%20require('fs')%3B%0Avar%20read%20%3D%20thunkify(fs.readFile)%3B%0Aread('package.json')(function(err%2C%20str)%7B%0A%2F%2F%20...%0A%7D)%3B%0A%60%60%60%0A%0A%E6%BA%90%E7%A0%81%3A%0A%60%60%60js%0Afunction%20thunkify(fn)%20%7B%0A%20%20return%20function()%20%7B%0A%20%20%20%20var%20args%20%3D%20new%20Array(arguments.length)%3B%0A%20%20%20%20var%20ctx%20%3D%20this%3B%0A%20%20%20%20for%20(var%20i%20%3D%200%3B%20i%20%3C%20args.length%3B%20%2B%2Bi)%20%7B%0A%20%20%20%20%20%20args%5Bi%5D%20%3D%20arguments%5Bi%5D%3B%0A%20%20%20%20%7D%0A%20%20%20%20return%20function%20(done)%20%7B%0Avar%20called%3B%0A%20%20%20%20%20%20args.push(function%20()%20%7B%0A%20%20%20%20%20%20%20%20if%20(called)%20return%3B%0A%20%20%20%20%20%20%20%20called%20%3D%20true%3B%0A%20%20%20%20%20%20%20%20done.apply(null%2C%20arguments)%3B%0A%7D)%3B%0A%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20fn.apply(ctx%2C%20args)%3B%0A%20%20%20%20%20%20%7D%20catch%20(err)%20%7B%0A%20%20%20%20%20%20%20%20done(err)%3B%0A%7D%20%7D%0A%7D%20%7D%3B%0A%60%60%60%0A%E5%AE%83%E7%9A%84%E6%BA%90%E7%A0%81%E4%B8%BB%E8%A6%81%E5%A4%9A%E4%BA%86%E4%B8%80%E4%B8%AA%E6%A3%80%E6%9F%A5%E6%9C%BA%E5%88%B6%EF%BC%8C%E5%8F%98%E9%87%8F%20called%20%E7%A1%AE%E4%BF%9D%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E5%8F%AA%E8%BF%90%E8%A1%8C%E4%B8%80%20%E6%AC%A1%E3%80%82%0A%0A%23%23%23%23%20Generator%20%E5%87%BD%E6%95%B0%E7%9A%84%E6%B5%81%E7%A8%8B%E7%AE%A1%E7%90%86%0AES6%20%E6%9C%89%E4%BA%86%20Generator%20%E5%87%BD%E6%95%B0%EF%BC%8CThunk%20%E5%87%BD%E6%95%B0%E7%8E%B0%E5%9C%A8%E5%8F%AF%E4%BB%A5%E7%94%A8%E4%BA%8E%20Generator%20%E5%87%BD%E6%95%B0%E7%9A%84%E8%87%AA%E5%8A%A8%E6%B5%81%E7%A8%8B%E7%AE%A1%E7%90%86%E3%80%82%0A%0A%60%60%60js%0Afunction*%20gen()%20%7B%0A%C2%A0%20%2F%2F%20...%0A%20%20%7D%0A%20%20%0Avar%20g%20%3D%20gen()%3B%0Avar%20res%20%3D%20g.next()%3B%0A%0Awhile(!res.done)%7B%0A%C2%A0%20console.log(res.value)%3B%0A%C2%A0%20res%20%3D%20g.next()%3B%0A%20%20%7D%0A%60%60%60%0A%E4%B8%8A%E9%9D%A2%E4%BB%A3%E7%A0%81%E4%B8%AD%EF%BC%8CGenerator%20%E5%87%BD%E6%95%B0%20gen%20%E4%BC%9A%E8%87%AA%E5%8A%A8%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%89%80%E6%9C%89%E6%AD%A5%E9%AA%A4%E3%80%82%0A%E4%BD%86%E6%98%AF%EF%BC%8C%E8%BF%99%E4%B8%8D%E9%80%82%E5%90%88%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%E3%80%82%E5%A6%82%E6%9E%9C%E5%BF%85%E9%A1%BB%E4%BF%9D%E8%AF%81%E5%89%8D%E4%B8%80%E6%AD%A5%E6%89%A7%E8%A1%8C%E5%AE%8C%EF%BC%8C%E6%89%8D%E8%83%BD%E6%89%A7%E8%A1%8C%E5%90%8E%E4%B8%80%20%E6%AD%A5%EF%BC%8C%E4%B8%8A%E9%9D%A2%E7%9A%84%E8%87%AA%E5%8A%A8%E6%89%A7%E8%A1%8C%E5%B0%B1%E4%B8%8D%E5%8F%AF%E8%A1%8C%E3%80%82%E8%BF%99%E6%97%B6%EF%BC%8CThunk%20%E5%87%BD%E6%95%B0%E5%B0%B1%E8%83%BD%E6%B4%BE%E4%B8%8A%E7%94%A8%E5%A4%84%E3%80%82%E4%BB%A5%E8%AF%BB%20%E5%8F%96%E6%96%87%E4%BB%B6%E4%B8%BA%E4%BE%8B%E3%80%82%E4%B8%8B%E9%9D%A2%E7%9A%84%20Generator%20%E5%87%BD%E6%95%B0%E5%B0%81%E8%A3%85%E4%BA%86%E4%B8%A4%E4%B8%AA%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%E3%80%82%0A%60%60%60js%0Avar%20fs%20%3D%20require('fs')%3B%0Avar%20thunkify%20%3D%20require('thunkify')%3B%0Avar%20readFileThunk%20%3D%20thunkify(fs.readFile)%3B%0Avar%20gen%20%3D%20function*%20()%7B%0A%20%20var%20r1%20%3D%20yield%20readFileThunk('%2Fetc%2Ffstab')%3B%0A%20%20console.log(r1.toString())%3B%0A%20%20var%20r2%20%3D%20yield%20readFileThunk('%2Fetc%2Fshells')%3B%0A%20%20console.log(r2.toString())%3B%0A%7D%3B%0A%60%60%60%0A%0A%E6%89%8B%E5%8A%A8%E6%89%A7%E8%A1%8C%E4%B8%8A%E9%9D%A2%E8%BF%99%E4%B8%AA%20Generator%20%E5%87%BD%E6%95%B0%3A%0A%60%60%60js%0Avar%20g%20%3D%20gen()%3B%0Avar%20r1%20%3D%20g.next()%3B%0Ar1.value(function%20(err%2C%20data)%20%7B%0A%20%20if%20(err)%20throw%20err%3B%0A%20%20var%20r2%20%3D%20g.next(data)%3B%0A%20%20r2.value(function%20(err%2C%20data)%20%7B%0A%20%20%20%20if%20(err)%20throw%20err%3B%0A%20%20%20%20g.next(data)%3B%0A%20%20%7D)%3B%0A%7D)%3B%0A%60%60%60%0AThunk%20%E5%87%BD%E6%95%B0%E7%9A%84%E8%87%AA%E5%8A%A8%E6%B5%81%E7%A8%8B%E7%AE%A1%E7%90%86%3A%0A%60%60%60js%0Afunction%20run(fn)%20%7B%0A%20%20var%20gen%20%3D%20fn()%3B%0A%20%20function%20next(err%2C%20data)%20%7B%0A%20%20%20%20var%20result%20%3D%20gen.next(data)%3B%0A%20%20%20%20if%20(result.done)%20return%3B%0A%20%20%20%20result.value(next)%3B%0A%7D%0Anext()%3B%20%7D%0Afunction*%20g()%20%7B%0A%20%20%2F%2F%20...%0A%7D%20run(g)%3B%0A%60%60%60%0A%E6%9C%89%E4%BA%86%E8%BF%99%E4%B8%AA%E6%89%A7%E8%A1%8C%E5%99%A8%EF%BC%8C%E6%89%A7%E8%A1%8C%20Generator%20%E5%87%BD%E6%95%B0%E6%96%B9%E4%BE%BF%E5%A4%9A%E4%BA%86%E3%80%82%E4%B8%8D%E7%AE%A1%E5%86%85%E9%83%A8%E6%9C%89%E5%A4%9A%E5%B0%91%E4%B8%AA%E5%BC%82%E6%AD%A5%20%E6%93%8D%E4%BD%9C%EF%BC%8C%E7%9B%B4%E6%8E%A5%E6%8A%8A%20Generator%20%E5%87%BD%E6%95%B0%E4%BC%A0%E5%85%A5%20run%20%E5%87%BD%E6%95%B0%E5%8D%B3%E5%8F%AF%E3%80%82%E5%BD%93%E7%84%B6%EF%BC%8C%E5%89%8D%E6%8F%90%E6%98%AF%E6%AF%8F%E4%B8%80%E4%B8%AA%20%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%EF%BC%8C%E9%83%BD%E8%A6%81%E6%98%AF%20Thunk%20%E5%87%BD%E6%95%B0%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%EF%BC%8C%E8%B7%9F%E5%9C%A8%20yield%20%E5%91%BD%E4%BB%A4%E5%90%8E%E9%9D%A2%E7%9A%84%E5%BF%85%20%E9%A1%BB%E6%98%AF%20Thunk%20%E5%87%BD%E6%95%B0%E3%80%82%0A%0A%23%23%23%23%20co%20%E6%A8%A1%E5%9D%97%0Aco%20%E6%A8%A1%E5%9D%97%E6%98%AF%E8%91%97%E5%90%8D%E7%A8%8B%E5%BA%8F%E5%91%98%20TJ%20Holowaychuk%20%E4%BA%8E2013%E5%B9%B46%E6%9C%88%E5%8F%91%E5%B8%83%E7%9A%84%E4%B8%80%E4%B8%AA%E5%B0%8F%E5%B7%A5%E5%85%B7%EF%BC%8C%20%E7%94%A8%E4%BA%8E%20Generator%20%E5%87%BD%E6%95%B0%E7%9A%84%E8%87%AA%E5%8A%A8%E6%89%A7%E8%A1%8C%E3%80%82%0Aco%20%E6%A8%A1%E5%9D%97%E5%8F%AF%E4%BB%A5%E8%AE%A9%E4%BD%A0%E4%B8%8D%E7%94%A8%E7%BC%96%E5%86%99%20Generator%20%E5%87%BD%E6%95%B0%E7%9A%84%E6%89%A7%E8%A1%8C%E5%99%A8%E3%80%82%0A%60%60%60js%0Avar%20co%20%3D%20require('co')%3B%0Aco(gen)%3B%0A%60%60%60%0A%0Aco%20%E5%87%BD%E6%95%B0%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%20Promise%20%E5%AF%B9%E8%B1%A1%EF%BC%8C%E5%9B%A0%E6%AD%A4%E5%8F%AF%E4%BB%A5%E7%94%A8%20then%20%E6%96%B9%E6%B3%95%E6%B7%BB%E5%8A%A0%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E3%80%82%0A%60%60%60js%0Aco(gen).then(function%20()%7B%20console.log('Generator%20%E5%87%BD%E6%95%B0%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%88%90')%3B%0A%7D)%3B%0A%60%60%60%0A%0A%23%23%23%23%20%E5%9F%BA%E4%BA%8E%20Promise%20%E5%AF%B9%E8%B1%A1%E7%9A%84%E8%87%AA%E5%8A%A8%E6%89%A7%E8%A1%8C%0A%0A%E8%BF%98%E6%98%AF%E6%B2%BF%E7%94%A8%E4%B8%8A%E9%9D%A2%E7%9A%84%E4%BE%8B%E5%AD%90%E3%80%82%E9%A6%96%E5%85%88%EF%BC%8C%E6%8A%8A%20fs%20%E6%A8%A1%E5%9D%97%E7%9A%84%20readFile%20%E6%96%B9%E6%B3%95%E5%8C%85%E8%A3%85%E6%88%90%E4%B8%80%E4%B8%AA%20Promise%20%E5%AF%B9%E8%B1%A1%E3%80%82%0A%60%60%60js%0Avar%20fs%20%3D%20require('fs')%3B%0Avar%20readFile%20%3D%20function%20(fileName)%7B%0A%20%20return%20new%20Promise(function%20(resolve%2C%20reject)%7B%0A%20%20%20%20fs.readFile(fileName%2C%20function(error%2C%20data)%7B%0A%20%20%20%20%20%20if%20(error)%20return%20reject(error)%3B%0A%20%20%20%20%20%20resolve(data)%3B%0A%7D)%3B%20%7D)%3B%0A%7D%3B%0Avar%20gen%20%3D%20function*%20()%7B%0A%20%20var%20f1%20%3D%20yield%20readFile('%2Fetc%2Ffstab')%3B%0A%20%20var%20f2%20%3D%20yield%20readFile('%2Fetc%2Fshells')%3B%0A%20%20console.log(f1.toString())%3B%0A%20%20console.log(f2.toString())%3B%0A%7D%3B%0A%60%60%60%0A%E7%84%B6%E5%90%8E%EF%BC%8C%E6%89%8B%E5%8A%A8%E6%89%A7%E8%A1%8C%E4%B8%8A%E9%9D%A2%E7%9A%84%20Generator%20%E5%87%BD%E6%95%B0%3A%0A%60%60%60js%0Avar%20g%20%3D%20gen()%3B%0Ag.next().value.then(function(data)%7B%0A%20%20g.next(data).value.then(function(data)%7B%0A%20%20%20%20g.next(data)%3B%0A%20%20%7D)%3B%0A%7D)%3B%0A%60%60%60%0A%0A%E8%87%AA%E5%8A%A8%E6%89%A7%E8%A1%8C%E5%99%A8%3A%0A%0A%60%60%60js%0Afunction%20run(gen)%7B%0A%20%20var%20g%20%3D%20gen()%3B%0A%20%20function%20next(data)%7B%0A%20%20%20%20var%20result%20%3D%20g.next(data)%3B%0A%20%20%20%20if%20(result.done)%20return%20result.value%3B%0A%20%20%20%20result.value.then(function(data)%7B%0A%20%20%20%20%20%20next(data)%3B%0A%20%20%20%20%7D)%3B%0A%7D%0Anext()%3B%20%7D%0Arun(gen)%3B%0A%60%60%60%0A%23%23%23%23%20co%20%E6%A8%A1%E5%9D%97%0A%23%23%23%23%23%20%E5%8E%9F%E7%90%86%0Aco%20%E6%A8%A1%E5%9D%97%E5%85%B6%E5%AE%9E%E5%B0%B1%E6%98%AF%E5%B0%86%E4%B8%A4%E7%A7%8D%E8%87%AA%E5%8A%A8%E6%89%A7%E8%A1%8C%E5%99%A8(Thunk%20%E5%87%BD%E6%95%B0%E5%92%8C%20Promise%20%E5%AF%B9%E8%B1%A1)%EF%BC%8C%E5%8C%85%20%E8%A3%85%E6%88%90%E4%B8%80%E4%B8%AA%E6%A8%A1%E5%9D%97%E3%80%82%E4%BD%BF%E7%94%A8%20co%20%E7%9A%84%E5%89%8D%E6%8F%90%E6%9D%A1%E4%BB%B6%E6%98%AF%EF%BC%8CGenerator%20%E5%87%BD%E6%95%B0%E7%9A%84%20yield%20%E5%91%BD%E4%BB%A4%E5%90%8E%20%E9%9D%A2%EF%BC%8C%E5%8F%AA%E8%83%BD%E6%98%AF%20Thunk%20%E5%87%BD%E6%95%B0%E6%88%96%20Promise%20%E5%AF%B9%E8%B1%A1%E3%80%82%E5%A6%82%E6%9E%9C%E6%95%B0%E7%BB%84%E6%88%96%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%88%90%E5%91%98%EF%BC%8C%E5%85%A8%E9%83%A8%20%E9%83%BD%E6%98%AF%20Promise%20%E5%AF%B9%E8%B1%A1%EF%BC%8C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%20co%0A%0A%23%23%23%23%23%20%E6%BA%90%E7%A0%81%0A%E9%A6%96%E5%85%88%EF%BC%8Cco%20%E5%87%BD%E6%95%B0%E6%8E%A5%E5%8F%97%20Generator%20%E5%87%BD%E6%95%B0%E4%BD%9C%E4%B8%BA%E5%8F%82%E6%95%B0%EF%BC%8C%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%20Promise%20%E5%AF%B9%E8%B1%A1%E3%80%82%0A%60%60%60js%0Afunction%20co(gen)%20%7B%0A%20%20var%20ctx%20%3D%20this%3B%0A%20%20return%20new%20Promise(function(resolve%2C%20reject)%20%7B%0A%7D)%3B%20%7D%0A%60%60%60%0A%E5%9C%A8%E8%BF%94%E5%9B%9E%E7%9A%84%20Promise%20%E5%AF%B9%E8%B1%A1%E9%87%8C%E9%9D%A2%EF%BC%8Cco%20%E5%85%88%E6%A3%80%E6%9F%A5%E5%8F%82%E6%95%B0%20gen%20%E6%98%AF%E5%90%A6%E4%B8%BA%20Generator%20%E5%87%BD%20%E6%95%B0%E3%80%82%E5%A6%82%E6%9E%9C%E6%98%AF%EF%BC%8C%E5%B0%B1%E6%89%A7%E8%A1%8C%E8%AF%A5%E5%87%BD%E6%95%B0%EF%BC%8C%E5%BE%97%E5%88%B0%E4%B8%80%E4%B8%AA%E5%86%85%E9%83%A8%E6%8C%87%E9%92%88%E5%AF%B9%E8%B1%A1%3B%E5%A6%82%E6%9E%9C%E4%B8%8D%E6%98%AF%E5%B0%B1%E8%BF%94%20%E5%9B%9E%EF%BC%8C%E5%B9%B6%E5%B0%86%20Promise%20%E5%AF%B9%E8%B1%A1%E7%9A%84%E7%8A%B6%E6%80%81%E6%94%B9%E4%B8%BA%20resolved%20%E3%80%82%0A%60%60%60js%0Afunction%20co(gen)%20%7B%0A%20%20var%20ctx%20%3D%20this%3B%0A%20%20return%20new%20Promise(function(resolve%2C%20reject)%20%7B%0A%20%20%20%20if%20(typeof%20gen%20%3D%3D%3D%20'function')%20gen%20%3D%20gen.call(ctx)%3B%0A%20%20%20%20if%20(!gen%20%7C%7C%20typeof%20gen.next%20!%3D%3D%20'function')%20return%0Aresolve(gen)%3B%0A%20%20%7D)%3B%0A%7D%0A%60%60%60%0A%E6%8E%A5%E7%9D%80%EF%BC%8Cco%20%E5%B0%86%20Generator%20%E5%87%BD%E6%95%B0%E7%9A%84%E5%86%85%E9%83%A8%E6%8C%87%E9%92%88%E5%AF%B9%E8%B1%A1%E7%9A%84%20next%20%E6%96%B9%E6%B3%95%EF%BC%8C%E5%8C%85%E8%A3%85%20%E6%88%90%20onFulfilled%20%E5%87%BD%E6%95%B0%E3%80%82%E8%BF%99%E4%B8%BB%E8%A6%81%E6%98%AF%E4%B8%BA%E4%BA%86%E8%83%BD%E5%A4%9F%E6%8D%95%E6%8D%89%E6%8A%9B%E5%87%BA%E7%9A%84%E9%94%99%E8%AF%AF%E3%80%82%0A%60%60%60js%0Afunction%20co(gen)%20%7B%0A%20%20var%20ctx%20%3D%20this%3B%0A%20%20return%20new%20Promise(function(resolve%2C%20reject)%20%7B%0A%20%20%20%20if%20(typeof%20gen%20%3D%3D%3D%20'function')%20gen%20%3D%20gen.call(ctx)%3B%0A%20%20%20%20if%20(!gen%20%7C%7C%20typeof%20gen.next%20!%3D%3D%20'function')%20return%0Aresolve(gen)%3B%0A%20%20%20%20onFulfilled()%3B%0A%20%20%20%20function%20onFulfilled(res)%20%7B%0Avar%20ret%3B%20try%20%7B%0A%20%20%20%20%20%20%20%20ret%20%3D%20gen.next(res)%3B%0A%20%20%20%20%20%20%7D%20catch%20(e)%20%7B%0A%20%20%20%20%20%20%20%20return%20reject(e)%3B%0A%20%20%20%20%20%20%7D%0Anext(ret)%3B%20%7D%0A%7D)%3B%20%7D%0A%60%60%60%0A%0A%E6%9C%80%E5%90%8E%EF%BC%8C%E5%B0%B1%E6%98%AF%E5%85%B3%E9%94%AE%E7%9A%84%20next%20%E5%87%BD%E6%95%B0%EF%BC%8C%E5%AE%83%E4%BC%9A%E5%8F%8D%E5%A4%8D%E8%B0%83%E7%94%A8%E8%87%AA%E8%BA%AB%E3%80%82%0A%60%60%60js%0Afunction%20next(ret)%20%7B%0A%20%20if%20(ret.done)%7B%0A%20%20%20%20return%20resolve(ret.value)%3B%0A%20%20%7D%0A%20%20var%20value%20%3D%20toPromise.call(ctx%2C%20ret.value)%3B%0A%20%20if%20(value%20%26%26%20isPromise(value))%7B%0A%20%20%20%20return%20value.then(onFulfilled%2C%20onRejected)%3B%0A%20%20%7D%0A%20%20return%20onRejected(%0A%20%20%20%20new%20TypeError(%0A%20%20%20%20%20%20'You%20may%20only%20yield%20a%20function%2C%20promise%2C%0Agenerator%2C%20array%2C%20or%20object%2C%20'%0A%20%20%20%20%20%20%2B%20'but%20the%20following%20object%20was%20passed%3A%20%22'%0A%20%20%20%20%20%20%2B%20String(ret.value)%0A%20%20%20%20%20%20%2B%20'%22'%0A%20%20%20%20)%0A%20%20)%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%20%E5%A4%84%E7%90%86%E5%B9%B6%E5%8F%91%E7%9A%84%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%0Aco%20%E6%94%AF%E6%8C%81%E5%B9%B6%E5%8F%91%E7%9A%84%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%EF%BC%8C%E5%8D%B3%E5%85%81%E8%AE%B8%E6%9F%90%E4%BA%9B%E6%93%8D%E4%BD%9C%E5%90%8C%E6%97%B6%E8%BF%9B%E8%A1%8C%EF%BC%8C%E7%AD%89%E5%88%B0%E5%AE%83%E4%BB%AC%E5%85%A8%E9%83%A8%E5%AE%8C%E6%88%90%EF%BC%8C%E6%89%8D%E8%BF%9B%E8%A1%8C%E4%B8%8B%E4%B8%80%E6%AD%A5%E3%80%82%0A%E8%BF%99%E6%97%B6%EF%BC%8C%E8%A6%81%E6%8A%8A%E5%B9%B6%E5%8F%91%E7%9A%84%E6%93%8D%E4%BD%9C%E9%83%BD%E6%94%BE%E5%9C%A8%E6%95%B0%E7%BB%84%E6%88%96%E5%AF%B9%E8%B1%A1%E9%87%8C%E9%9D%A2%EF%BC%8C%E8%B7%9F%E5%9C%A8%20yield%20%E8%AF%AD%E5%8F%A5%E5%90%8E%E9%9D%A2%E3%80%82%0A%60%60%60js%0A%2F%2F%20%E6%95%B0%E7%BB%84%E7%9A%84%E5%86%99%E6%B3%951%0Aco(function*%20()%20%7B%0A%20%20var%20res%20%3D%20yield%20%5B%0A%20%20%20%20Promise.resolve(1)%2C%0A%20%20%20%20Promise.resolve(2)%0A%20%20%5D%3B%0A%20%20console.log(res)%3B%0A%7D).catch(onerror)%3B%0A%0A%2F%2F%20%E6%95%B0%E7%BB%84%E7%9A%84%E5%86%99%E6%B3%952%0Aco(function*%20()%20%7B%0A%20%20var%20values%20%3D%20%5Bn1%2C%20n2%2C%20n3%5D%3B%0A%20%20yield%20values.map(somethingAsync)%3B%0A%7D)%3B%0Afunction*%20somethingAsync(x)%20%7B%0A%20%20%2F%2F%20do%20something%20async%0A%20%20return%20y%0A%7D%0A%0A%2F%2F%20%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%86%99%E6%B3%95%0Aco(function*%20()%20%7B%0A%20%20var%20res%20%3D%20yield%20%7B%0A%20%20%20%201%3A%20Promise.resolve(1)%2C%0A%20%20%20%202%3A%20Promise.resolve(2)%2C%0A%20%20%7D%3B%0A%20%20console.log(res)%3B%0A%7D).catch(onerror)%3B%0A%0A%60%60%60%0A%0A%23%23%20async%20%E5%87%BD%E6%95%B0%0A%0AES2017%20%E6%A0%87%E5%87%86%E5%BC%95%E5%85%A5%E4%BA%86%20async%20%E5%87%BD%E6%95%B0%EF%BC%8C%E4%BD%BF%E5%BE%97%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%E5%8F%98%E5%BE%97%E6%9B%B4%E5%8A%A0%E6%96%B9%E4%BE%BF%E3%80%82%20async%20%E5%87%BD%E6%95%B0%E6%98%AF%E4%BB%80%E4%B9%88%3F%E4%B8%80%E5%8F%A5%E8%AF%9D%EF%BC%8C%E5%AE%83%E5%B0%B1%E6%98%AF%20Generator%20%E5%87%BD%E6%95%B0%E7%9A%84%E8%AF%AD%E6%B3%95%E7%B3%96%E3%80%82%0A%0A%E5%89%8D%E6%96%87%E6%9C%89%E4%B8%80%E4%B8%AA%20Generator%20%E5%87%BD%E6%95%B0%EF%BC%8C%E4%BE%9D%E6%AC%A1%E8%AF%BB%E5%8F%96%E4%B8%A4%E4%B8%AA%E6%96%87%E4%BB%B6%E3%80%82%0A%60%60%60js%0Aconst%20fs%20%3D%20require('fs')%3B%0Aconst%20readFile%20%3D%20function%20(fileName)%20%7B%0A%20%20return%20new%20Promise(function%20(resolve%2C%20reject)%20%7B%0A%20%20%20%20fs.readFile(fileName%2C%20function(error%2C%20data)%20%7B%0A%20%20%20%20%20%20if%20(error)%20return%20reject(error)%3B%0A%20%20%20%20%20%20resolve(data)%3B%0A%20%20%20%20%7D)%3B%0A%7D)%3B%20%7D%3B%0Aconst%20gen%20%3D%20function*%20()%20%7B%0A%20%20const%20f1%20%3D%20yield%20readFile('%2Fetc%2Ffstab')%3B%0A%20%20const%20f2%20%3D%20yield%20readFile('%2Fetc%2Fshells')%3B%0A%20%20console.log(f1.toString())%3B%0A%20%20console.log(f2.toString())%3B%0A%7D%3B%0A%60%60%60%0A%E5%86%99%E6%88%90%20async%20%E5%87%BD%E6%95%B0%EF%BC%8C%E5%B0%B1%E6%98%AF%E4%B8%8B%E9%9D%A2%E8%BF%99%E6%A0%B7%E3%80%82%0A%60%60%60js%0Aconst%20asyncReadFile%20%3D%20async%20function%20()%20%7B%0A%20%20const%20f1%20%3D%20await%20readFile('%2Fetc%2Ffstab')%3B%0A%20%20const%20f2%20%3D%20await%20readFile('%2Fetc%2Fshells')%3B%0A%20%20console.log(f1.toString())%3B%0A%20%20console.log(f2.toString())%3B%0A%7D%3B%0A%60%60%60%0Aasync%20%E5%87%BD%E6%95%B0%E5%B0%B1%E6%98%AF%E5%B0%86%20Generator%20%E5%87%BD%E6%95%B0%E7%9A%84%E6%98%9F%E5%8F%B7(%20*%20)%E6%9B%BF%20%E6%8D%A2%E6%88%90%20async%20%EF%BC%8C%E5%B0%86%20yield%20%E6%9B%BF%E6%8D%A2%E6%88%90%20await%20%EF%BC%8C%E4%BB%85%E6%AD%A4%E8%80%8C%E5%B7%B2%E3%80%82%0A%0Aasync%20%E5%87%BD%E6%95%B0%E5%AF%B9%20Generator%20%E5%87%BD%E6%95%B0%E7%9A%84%E6%94%B9%E8%BF%9B%E3%80%82%0A(1)%E5%86%85%E7%BD%AE%E6%89%A7%E8%A1%8C%E5%99%A8%E3%80%82%0A%20async%20%E5%87%BD%E6%95%B0%E7%9A%84%E6%89%A7%E8%A1%8C%EF%BC%8C%E4%B8%8E%E6%99%AE%E9%80%9A%E5%87%BD%20%E6%95%B0%E4%B8%80%E6%A8%A1%E4%B8%80%E6%A0%B7%0A%20%0A%60%60%60js%0AasyncReadFile()%3B%0A%60%60%60%0A(2)%E6%9B%B4%E5%A5%BD%E7%9A%84%E8%AF%AD%E4%B9%89%E3%80%82%0A(3)%E6%9B%B4%E5%B9%BF%E7%9A%84%E9%80%82%E7%94%A8%E6%80%A7%E3%80%82%0Aasync%20%E5%87%BD%E6%95%B0%E7%9A%84%20await%20%E5%91%BD%E4%BB%A4%E5%90%8E%E9%9D%A2%EF%BC%8C%E5%8F%AF%E4%BB%A5%E6%98%AFPromise%20%E5%AF%B9%E8%B1%A1%E5%92%8C%E5%8E%9F%E5%A7%8B%E7%B1%BB%E5%9E%8B%E7%9A%84%20%E5%80%BC(%E6%95%B0%E5%80%BC%E3%80%81%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%92%8C%E5%B8%83%E5%B0%94%E5%80%BC%EF%BC%8C%E4%BD%86%E8%BF%99%E6%97%B6%E7%AD%89%E5%90%8C%E4%BA%8E%E5%90%8C%E6%AD%A5%E6%93%8D%E4%BD%9C)%E3%80%82%0A(4)%E8%BF%94%E5%9B%9E%E5%80%BC%E6%98%AF%20Promise%E3%80%82%0A%0A%23%23%23%23%20%E5%9F%BA%E6%9C%AC%E7%94%A8%E6%B3%95%0A%0Aasync%20%E5%87%BD%E6%95%B0%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%20Promise%20%E5%AF%B9%E8%B1%A1%EF%BC%8C%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%20then%20%E6%96%B9%E6%B3%95%E6%B7%BB%E5%8A%A0%E5%9B%9E%E8%B0%83%E5%87%BD%20%E6%95%B0%E3%80%82%E5%BD%93%E5%87%BD%E6%95%B0%E6%89%A7%E8%A1%8C%E7%9A%84%E6%97%B6%E5%80%99%EF%BC%8C%E4%B8%80%E6%97%A6%E9%81%87%E5%88%B0%20await%20%E5%B0%B1%E4%BC%9A%E5%85%88%E8%BF%94%E5%9B%9E%EF%BC%8C%E7%AD%89%E5%88%B0%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%20%E5%AE%8C%E6%88%90%EF%BC%8C%E5%86%8D%E6%8E%A5%E7%9D%80%E6%89%A7%E8%A1%8C%E5%87%BD%E6%95%B0%E4%BD%93%E5%86%85%E5%90%8E%E9%9D%A2%E7%9A%84%E8%AF%AD%E5%8F%A5%E3%80%82%0A%60%60%60js%0Afunction%20timeout(ms)%20%7B%0A%20%20return%20new%20Promise((resolve)%20%3D%3E%20%7B%0A%20%20%20%20setTimeout(resolve%2C%20ms)%3B%0A%20%20%7D)%3B%0A%7D%0Aasync%20function%20asyncPrint(value%2C%20ms)%20%7B%0A%20%20await%20timeout(ms)%3B%0A%20%20console.log(value)%3B%0A%7D%0AasyncPrint('hello%20world'%2C%2050)%3B%0A%60%60%60%0A%E4%B8%8A%E9%9D%A2%E4%BB%A3%E7%A0%81%E6%8C%87%E5%AE%9A50%E6%AF%AB%E7%A7%92%E4%BB%A5%E5%90%8E%EF%BC%8C%E8%BE%93%E5%87%BA%20hello%20world%20%E3%80%82%0A%0Aasync%20%E5%87%BD%E6%95%B0%E6%9C%89%E5%A4%9A%E7%A7%8D%E4%BD%BF%E7%94%A8%E5%BD%A2%E5%BC%8F%E3%80%82%0A%60%60%60js%0A%2F%2F%20%E5%87%BD%E6%95%B0%E5%A3%B0%E6%98%8E%0Aasync%20function%20foo()%20%7B%7D%0A%2F%2F%20%E5%87%BD%E6%95%B0%E8%A1%A8%E8%BE%BE%E5%BC%8F%0Aconst%20foo%20%3D%20async%20function%20()%20%7B%7D%3B%0A%2F%2F%20%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%96%B9%E6%B3%95%0Alet%20obj%20%3D%20%7B%20async%20foo()%20%7B%7D%20%7D%3B%0Aobj.foo().then(...)%0A%2F%2F%20Class%20%E7%9A%84%E6%96%B9%E6%B3%95%20class%20Storage%20%7B%0A%20%20constructor()%20%7B%0A%20%20%20%20this.cachePromise%20%3D%20caches.open('avatars')%3B%0A%7D%0A%20%20async%20getAvatar(name)%20%7B%0A%20%20%20%20const%20cache%20%3D%20await%20this.cachePromise%3B%0A%20%20%20%20return%20cache.match(%60%2Favatars%2F%24%7Bname%7D.jpg%60)%3B%0A%7D%20%7D%0Aconst%20storage%20%3D%20new%20Storage()%3B%0Astorage.getAvatar('jake').then(...)%3B%0A%2F%2F%20%E7%AE%AD%E5%A4%B4%E5%87%BD%E6%95%B0%0Aconst%20foo%20%3D%20async%20()%20%3D%3E%20%7B%7D%3B%0A%60%60%60%0A%0A%23%23%23%23%20%E8%AF%AD%E6%B3%95%0A%23%23%23%23%23%20%E8%BF%94%E5%9B%9E%20Promise%20%E5%AF%B9%E8%B1%A1%0Aasync%20%E5%87%BD%E6%95%B0%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%20Promise%20%E5%AF%B9%E8%B1%A1%E3%80%82%0Aasync%20%E5%87%BD%E6%95%B0%E5%86%85%E9%83%A8%20return%20%E8%AF%AD%E5%8F%A5%E8%BF%94%E5%9B%9E%E7%9A%84%E5%80%BC%EF%BC%8C%E4%BC%9A%E6%88%90%E4%B8%BA%20then%20%E6%96%B9%E6%B3%95%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%20%E7%9A%84%E5%8F%82%E6%95%B0%E3%80%82%0A%60%60%60js%0Aasync%20function%20f()%20%7B%0A%20%20return%20'hello%20world'%3B%0A%7D%0Af().then(v%20%3D%3E%20console.log(v))%0A%2F%2F%20%22hello%20world%22%0A%60%60%60%0A%0A%23%23%23%23%23%20Promise%20%E5%AF%B9%E8%B1%A1%E7%9A%84%E7%8A%B6%E6%80%81%E5%8F%98%E5%8C%96%0Aasync%20%E5%87%BD%E6%95%B0%E8%BF%94%E5%9B%9E%E7%9A%84%20Promise%20%E5%AF%B9%E8%B1%A1%EF%BC%8C%E5%BF%85%E9%A1%BB%E7%AD%89%E5%88%B0%E5%86%85%E9%83%A8%E6%89%80%E6%9C%89%20await%20%E5%91%BD%E4%BB%A4%E5%90%8E%E9%9D%A2%20%E7%9A%84%20Promise%20%E5%AF%B9%E8%B1%A1%E6%89%A7%E8%A1%8C%E5%AE%8C%EF%BC%8C%E6%89%8D%E4%BC%9A%E5%8F%91%E7%94%9F%E7%8A%B6%E6%80%81%E6%94%B9%E5%8F%98%EF%BC%8C%E9%99%A4%E9%9D%9E%E9%81%87%E5%88%B0%20return%20%E8%AF%AD%E5%8F%A5%E6%88%96%20%E8%80%85%E6%8A%9B%E5%87%BA%E9%94%99%E8%AF%AF%E3%80%82%0A%0A%23%23%23%23%23%20await%20%E5%91%BD%E4%BB%A4%0A%E6%AD%A3%E5%B8%B8%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%20await%20%E5%91%BD%E4%BB%A4%E5%90%8E%E9%9D%A2%E6%98%AF%E4%B8%80%E4%B8%AA%20Promise%20%E5%AF%B9%E8%B1%A1%E3%80%82%E5%A6%82%E6%9E%9C%E4%B8%8D%E6%98%AF%EF%BC%8C%E4%BC%9A%E8%A2%AB%E8%BD%AC%0A%E6%88%90%E4%B8%80%E4%B8%AA%E7%AB%8B%E5%8D%B3%20resolve%20%E7%9A%84%20Promise%20%E5%AF%B9%E8%B1%A1%E3%80%82%0A%0Aawait%20%E5%91%BD%E4%BB%A4%E5%90%8E%E9%9D%A2%E7%9A%84%20Promise%20%E5%AF%B9%E8%B1%A1%E5%A6%82%E6%9E%9C%E5%8F%98%E4%B8%BA%20reject%20%E7%8A%B6%E6%80%81%EF%BC%8C%20%E5%88%99%20reject%20%E7%9A%84%E5%8F%82%E6%95%B0%E4%BC%9A%E8%A2%AB%20catch%20%E6%96%B9%E6%B3%95%E7%9A%84%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E6%8E%A5%E6%94%B6%E5%88%B0%E3%80%82%0A%60%60%60js%0Aasync%20function%20f()%20%7B%0Aawait%20Promise.reject('%E5%87%BA%E9%94%99%E4%BA%86')%3B%0A%7D%0Af()%0A.then(v%20%3D%3E%20console.log(v))%20.catch(e%20%3D%3E%20console.log(e))%20%2F%2F%20%E5%87%BA%E9%94%99%E4%BA%86%0A%60%60%60%0A%0A%E5%8F%AA%E8%A6%81%E4%B8%80%E4%B8%AA%20await%20%E8%AF%AD%E5%8F%A5%E5%90%8E%E9%9D%A2%E7%9A%84%20Promise%20%E5%8F%98%E4%B8%BA%20reject%20%EF%BC%8C%E9%82%A3%E4%B9%88%E6%95%B4%20%E4%B8%AA%20async%20%E5%87%BD%E6%95%B0%E9%83%BD%E4%BC%9A%E4%B8%AD%E6%96%AD%E6%89%A7%E8%A1%8C%E3%80%82%0A%0A%23%23%23%23%20%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86%0A%E5%A6%82%E6%9E%9C%20await%20%E5%90%8E%E9%9D%A2%E7%9A%84%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%E5%87%BA%E9%94%99%EF%BC%8C%E9%82%A3%E4%B9%88%E7%AD%89%E5%90%8C%E4%BA%8E%20async%20%E5%87%BD%E6%95%B0%E8%BF%94%E5%9B%9E%E7%9A%84%0APromise%20%E5%AF%B9%E8%B1%A1%E8%A2%AB%20reject%20%E3%80%82%0A%E9%98%B2%E6%AD%A2%E5%87%BA%E9%94%99%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E4%B9%9F%E6%98%AF%E5%B0%86%E5%85%B6%E6%94%BE%E5%9C%A8%20try...catch%20%E4%BB%A3%E7%A0%81%E5%9D%97%E4%B9%8B%E4%B8%AD%E3%80%82%0A%60%60%60js%0Aasync%20function%20f()%20%7B%0A%20%20try%20%7B%0Aawait%20new%20Promise(function%20(resolve%2C%20reject)%20%7B%20throw%20new%20Error('%E5%87%BA%E9%94%99%E4%BA%86')%3B%0A%20%20%20%20%7D)%3B%0A%20%20%7D%20catch(e)%20%7B%0A%20%20%7D%0A%20%20return%20await('hello%20world')%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%20%E4%BD%BF%E7%94%A8%E6%B3%A8%E6%84%8F%E7%82%B9%0A%E7%AC%AC%E4%B8%80%E7%82%B9%EF%BC%8C%E5%89%8D%E9%9D%A2%E5%B7%B2%E7%BB%8F%E8%AF%B4%E8%BF%87%EF%BC%8C%20await%20%E5%91%BD%E4%BB%A4%E5%90%8E%E9%9D%A2%E7%9A%84%20Promise%20%E5%AF%B9%E8%B1%A1%EF%BC%8C%E8%BF%90%E8%A1%8C%E7%BB%93%E6%9E%9C%20%E5%8F%AF%E8%83%BD%E6%98%AF%20rejected%20%EF%BC%8C%E6%89%80%E4%BB%A5%E6%9C%80%E5%A5%BD%E6%8A%8A%20await%20%E5%91%BD%E4%BB%A4%E6%94%BE%E5%9C%A8%20try...catch%20%E4%BB%A3%E7%A0%81%20%E5%9D%97%E4%B8%AD%E3%80%82%0A%0A%E7%AC%AC%E4%BA%8C%E7%82%B9%EF%BC%8C%E5%A4%9A%E4%B8%AA%20await%20%E5%91%BD%E4%BB%A4%E5%90%8E%E9%9D%A2%E7%9A%84%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%B8%8D%E5%AD%98%E5%9C%A8%E7%BB%A7%E5%8F%91%E5%85%B3%E7%B3%BB%EF%BC%8C%E6%9C%80%20%E5%A5%BD%E8%AE%A9%E5%AE%83%E4%BB%AC%E5%90%8C%E6%97%B6%E8%A7%A6%E5%8F%91%E3%80%82%0A%60%60%60js%0A%2F%2F%20%E5%86%99%E6%B3%95%E4%B8%80%0Alet%20%5Bfoo%2C%20bar%5D%20%3D%20await%20Promise.all(%5BgetFoo()%2C%0AgetBar()%5D)%3B%0A%2F%2F%20%E5%86%99%E6%B3%95%E4%BA%8C%0Alet%20fooPromise%20%3D%20getFoo()%3B%0Alet%20barPromise%20%3D%20getBar()%3B%0Alet%20foo%20%3D%20await%20fooPromise%3B%0Alet%20bar%20%3D%20await%20barPromise%3B%0A%60%60%60%0A%E7%AC%AC%E4%B8%89%E7%82%B9%EF%BC%8C%20await%20%E5%91%BD%E4%BB%A4%E5%8F%AA%E8%83%BD%E7%94%A8%E5%9C%A8%20async%20%E5%87%BD%E6%95%B0%E4%B9%8B%E4%B8%AD%EF%BC%8C%E5%A6%82%E6%9E%9C%E7%94%A8%E5%9C%A8%E6%99%AE%E9%80%9A%E5%87%BD%E6%95%B0%EF%BC%8C%20%E5%B0%B1%E4%BC%9A%E6%8A%A5%E9%94%99%E3%80%82%0A%0A%23%23%23%23%20async%20%E5%87%BD%E6%95%B0%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86%0A%60%60%60js%0Aasync%20function%20fn(args)%20%7B%0A%20%20%2F%2F%20...%0A%7D%0A%2F%2F%20%E7%AD%89%E5%90%8C%E4%BA%8E%0Afunction%20fn(args)%20%7B%0A%20%20return%20spawn(function*%20()%20%7B%0A%2F%2F%20...%0A%7D)%3B%20%7D%0A%0Afunction%20spawn(genF)%20%7B%0A%20%20return%20new%20Promise(function(resolve%2C%20reject)%20%7B%0A%20%20%20%20const%20gen%20%3D%20genF()%3B%0A%20%20%20%20function%20step(nextF)%20%7B%0A%20%20%20%20%20%20let%20next%3B%0A%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20next%20%3D%20nextF()%3B%0A%20%20%20%20%20%20%7D%20catch(e)%20%7B%0A%20%20%20%20%20%20%20%20return%20reject(e)%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20if(next.done)%20%7B%0A%20%20%20%20%20%20%20%20return%20resolve(next.value)%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20Promise.resolve(next.value).then(function(v)%20%7B%0A%20%20%20%20%20%20%20%20step(function()%20%7B%20return%20gen.next(v)%3B%20%7D)%3B%0A%20%20%20%20%20%20%7D%2C%20function(e)%20%7B%0A%20%20%20%20%20%20%20%20step(function()%20%7B%20return%20gen.throw(e)%3B%20%7D)%3B%0A%20%20%20%20%20%20%7D)%3B%0A%7D%0A%20%20%20%20step(function()%20%7B%20return%20gen.next(undefined)%3B%20%7D)%3B%0A%20%20%7D)%3B%0A%7D%0A%60%60%60%0A%23%23%23%23%23%20%E5%AE%9E%E4%BE%8B%3A%E6%8C%89%E9%A1%BA%E5%BA%8F%E5%AE%8C%E6%88%90%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%0A%60%60%60js%0Aasync%20function%20logInOrder(urls)%20%7B%0A%2F%2F%20%E5%B9%B6%E5%8F%91%E8%AF%BB%E5%8F%96%E8%BF%9C%E7%A8%8BURL%0Aconst%20textPromises%20%3D%20urls.map(async%20url%20%3D%3E%20%7B%0A%20%20%20%20const%20response%20%3D%20await%20fetch(url)%3B%0A%20%20%20%20return%20response.text()%3B%0A%20%20%7D)%3B%0A%2F%2F%20%E6%8C%89%E6%AC%A1%E5%BA%8F%E8%BE%93%E5%87%BA%0A%20%20for%20(const%20textPromise%20of%20textPromises)%20%7B%0A%20%20%20%20console.log(await%20textPromise)%3B%0A%7D%20%7D%0A%60%60%60%0A%E4%B8%8A%E9%9D%A2%E4%BB%A3%E7%A0%81%E4%B8%AD%EF%BC%8C%E8%99%BD%E7%84%B6%20map%20%E6%96%B9%E6%B3%95%E7%9A%84%E5%8F%82%E6%95%B0%E6%98%AF%20async%20%E5%87%BD%E6%95%B0%EF%BC%8C%E4%BD%86%E5%AE%83%E6%98%AF%E5%B9%B6%E5%8F%91%E6%89%A7%E8%A1%8C%20%E7%9A%84%EF%BC%8C%E5%9B%A0%E4%B8%BA%E5%8F%AA%E6%9C%89%20async%20%E5%87%BD%E6%95%B0%E5%86%85%E9%83%A8%E6%98%AF%E7%BB%A7%E5%8F%91%E6%89%A7%E8%A1%8C%EF%BC%8C%E5%A4%96%E9%83%A8%E4%B8%8D%E5%8F%97%E5%BD%B1%E5%93%8D%E3%80%82%0A%0A%23%23%20Class%20%E7%9A%84%E5%9F%BA%E6%9C%AC%E8%AF%AD%E6%B3%95%0A%0AES6%20%E7%9A%84%20class%20%E5%8F%AF%E4%BB%A5%E7%9C%8B%E4%BD%9C%E5%8F%AA%E6%98%AF%E4%B8%80%E4%B8%AA%E8%AF%AD%E6%B3%95%E7%B3%96%EF%BC%8C%E5%AE%83%E7%9A%84%E7%BB%9D%E5%A4%A7%E9%83%A8%E5%88%86%E5%8A%9F%E8%83%BD%EF%BC%8C%20ES5%20%E9%83%BD%E5%8F%AF%E4%BB%A5%E5%81%9A%E5%88%B0%EF%BC%8C%E6%96%B0%E7%9A%84%20class%20%E5%86%99%E6%B3%95%E5%8F%AA%E6%98%AF%E8%AE%A9%E5%AF%B9%E8%B1%A1%E5%8E%9F%E5%9E%8B%E7%9A%84%E5%86%99%E6%B3%95%E6%9B%B4%E5%8A%A0%E6%B8%85%E6%99%B0%E3%80%81%E6%9B%B4%20%E5%83%8F%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%BC%96%E7%A8%8B%E7%9A%84%E8%AF%AD%E6%B3%95%E8%80%8C%E5%B7%B2%E3%80%82%0A%60%60%60js%0A%2F%2F%E5%AE%9A%E4%B9%89%E7%B1%BB%0Aclass%20Point%20%7B%0A%20%20constructor(x%2C%20y)%20%7B%0A%20%20%20%20this.x%20%3D%20x%3B%0A%20%20%20%20this.y%20%3D%20y%3B%0A%7D%0A%20%20toString()%20%7B%0A%20%20%20%20return%20'('%20%2B%20this.x%20%2B%20'%2C%20'%20%2B%20this.y%20%2B%20')'%3B%0A%7D%20%7D%0A%60%60%60%0A%0A%E5%AE%9A%20%E4%B9%89%E2%80%9C%E7%B1%BB%E2%80%9D%E7%9A%84%E6%96%B9%E6%B3%95%E7%9A%84%E6%97%B6%E5%80%99%EF%BC%8C%E5%89%8D%E9%9D%A2%E4%B8%8D%E9%9C%80%E8%A6%81%E5%8A%A0%E4%B8%8A%20function%20%E8%BF%99%E4%B8%AA%E5%85%B3%E9%94%AE%E5%AD%97%EF%BC%8C%E7%9B%B4%E6%8E%A5%E6%8A%8A%E5%87%BD%E6%95%B0%E5%AE%9A%E4%B9%89%E6%94%BE%E8%BF%9B%E5%8E%BB%E4%BA%86%E5%B0%B1%E5%8F%AF%E4%BB%A5%E4%BA%86%E3%80%82%E5%8F%A6%E5%A4%96%EF%BC%8C%E6%96%B9%E6%B3%95%E4%B9%8B%E9%97%B4%E4%B8%8D%E9%9C%80%E8%A6%81%E9%80%97%E5%8F%B7%E5%88%86%E9%9A%94%EF%BC%8C%E5%8A%A0%E4%BA%86%E4%BC%9A%E6%8A%A5%E9%94%99%E3%80%82%0A%0A%60%60%60js%0Aclass%20Point%20%7B%0A%20%20%2F%2F%20...%0A%7D%0Atypeof%20Point%20%2F%2F%20%22function%22%0APoint%20%3D%3D%3D%20Point.prototype.constructor%20%2F%2F%20true%0A%60%60%60%0A%E4%B8%8A%E9%9D%A2%E4%BB%A3%E7%A0%81%E8%A1%A8%E6%98%8E%EF%BC%8C%E7%B1%BB%E7%9A%84%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E5%B0%B1%E6%98%AF%E5%87%BD%E6%95%B0%EF%BC%8C%E7%B1%BB%E6%9C%AC%E8%BA%AB%E5%B0%B1%E6%8C%87%E5%90%91%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E3%80%82%0A%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E7%9A%84%20prototype%20%E5%B1%9E%E6%80%A7%EF%BC%8C%E5%9C%A8%20ES6%20%E7%9A%84%E2%80%9C%E7%B1%BB%E2%80%9D%E4%B8%8A%E9%9D%A2%E7%BB%A7%E7%BB%AD%E5%AD%98%E5%9C%A8%E3%80%82%E4%BA%8B%E5%AE%9E%E4%B8%8A%EF%BC%8C%20%E7%B1%BB%E7%9A%84%E6%89%80%E6%9C%89%E6%96%B9%E6%B3%95%E9%83%BD%E5%AE%9A%E4%B9%89%E5%9C%A8%E7%B1%BB%E7%9A%84%20prototype%20%E5%B1%9E%E6%80%A7%E4%B8%8A%E9%9D%A2%E3%80%82%0A%60%60%60js%0Aclass%20Point%20%7B%0A%20%20constructor()%20%7B%0A%2F%2F%20...%0A%7D%0AtoString()%20%7B%0A%2F%2F%20...%0A%7D%0AtoValue()%20%7B%0A%2F%2F%20...%0A%7D%20%7D%0A%2F%2F%20%E7%AD%89%E5%90%8C%E4%BA%8E%0APoint.prototype%20%3D%20%7B%0A%20%20constructor()%20%7B%7D%2C%0A%20%20toString()%20%7B%7D%2C%0A%20%20toValue()%20%7B%7D%2C%0A%7D%3B%0A%60%60%60%0A%0A%E5%9C%A8%E7%B1%BB%E7%9A%84%E5%AE%9E%E4%BE%8B%E4%B8%8A%E9%9D%A2%E8%B0%83%E7%94%A8%E6%96%B9%E6%B3%95%EF%BC%8C%E5%85%B6%E5%AE%9E%E5%B0%B1%E6%98%AF%E8%B0%83%E7%94%A8%E5%8E%9F%E5%9E%8B%E4%B8%8A%E7%9A%84%E6%96%B9%E6%B3%95%E3%80%82%0A%0A**%E7%B1%BB%E7%9A%84%E5%86%85%E9%83%A8%E6%89%80%E6%9C%89%E5%AE%9A%E4%B9%89%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E9%83%BD%E6%98%AF%E4%B8%8D%E5%8F%AF%E6%9E%9A%E4%B8%BE%E7%9A%84(non-enumerable)%E3%80%82**%0A%0A%E7%B1%BB%E7%9A%84%E5%B1%9E%E6%80%A7%E5%90%8D%EF%BC%8C%E5%8F%AF%E4%BB%A5%E9%87%87%E7%94%A8%E8%A1%A8%E8%BE%BE%E5%BC%8F%E3%80%82%0A%60%60%60JS%0Alet%20methodName%20%3D%20'getArea'%3B%0Aclass%20Square%20%7B%0A%20%20constructor(length)%20%7B%0A%2F%2F%20...%0A%7D%0A%20%20%5BmethodName%5D()%20%7B%0A%2F%2F%20...%0A%7D%20%7D%0A%60%60%60%0A%0A%23%23%23%23%20%E4%B8%A5%E6%A0%BC%E6%A8%A1%E5%BC%8F%0A%E7%B1%BB%E5%92%8C%E6%A8%A1%E5%9D%97%E7%9A%84%E5%86%85%E9%83%A8%EF%BC%8C%E9%BB%98%E8%AE%A4%E5%B0%B1%E6%98%AF%E4%B8%A5%E6%A0%BC%E6%A8%A1%E5%BC%8F%EF%BC%8C%E5%8F%AA%E8%A6%81%E4%BD%A0%E7%9A%84%E4%BB%A3%E7%A0%81%E5%86%99%E5%9C%A8%E7%B1%BB%E6%88%96%E6%A8%A1%E5%9D%97%E4%B9%8B%E4%B8%AD%EF%BC%8C%E5%B0%B1%E5%8F%AA%E6%9C%89%E4%B8%A5%E6%A0%BC%E6%A8%A1%E5%BC%8F%E5%8F%AF%E7%94%A8%E3%80%82%E8%80%83%E8%99%91%E5%88%B0%E6%9C%AA%E6%9D%A5%E6%89%80%E6%9C%89%E7%9A%84%E4%BB%A3%E7%A0%81%EF%BC%8C%E5%85%B6%E5%AE%9E%E9%83%BD%E6%98%AF%E8%BF%90%E8%A1%8C%E5%9C%A8%E6%A8%A1%E5%9D%97%E4%B9%8B%E4%B8%AD%EF%BC%8C%E6%89%80%E4%BB%A5%20ES6%20%E5%AE%9E%E9%99%85%E4%B8%8A%E6%8A%8A%20%E6%95%B4%E4%B8%AA%E8%AF%AD%E8%A8%80%E5%8D%87%E7%BA%A7%E5%88%B0%E4%BA%86%E4%B8%A5%E6%A0%BC%E6%A8%A1%E5%BC%8F%E3%80%82%0A%0A%23%23%23%23%20constructor%20%E6%96%B9%E6%B3%95%0A%0Aconstructor%20%E6%96%B9%E6%B3%95%E6%98%AF%E7%B1%BB%E7%9A%84%E9%BB%98%E8%AE%A4%E6%96%B9%E6%B3%95%EF%BC%8C%E9%80%9A%E8%BF%87%20new%20%E5%91%BD%E4%BB%A4%E7%94%9F%E6%88%90%E5%AF%B9%E8%B1%A1%E5%AE%9E%E4%BE%8B%E6%97%B6%EF%BC%8C%20%E8%87%AA%E5%8A%A8%E8%B0%83%E7%94%A8%E8%AF%A5%E6%96%B9%E6%B3%95%E3%80%82%E4%B8%80%E4%B8%AA%E7%B1%BB%E5%BF%85%E9%A1%BB%E6%9C%89%20constructor%20%E6%96%B9%E6%B3%95%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E6%98%BE%E5%BC%8F%E5%AE%9A%20%E4%B9%89%EF%BC%8C%E4%B8%80%E4%B8%AA%E7%A9%BA%E7%9A%84%20constructor%20%E6%96%B9%E6%B3%95%E4%BC%9A%E8%A2%AB%E9%BB%98%E8%AE%A4%E6%B7%BB%E5%8A%A0%E3%80%82%0A%60%60%60js%0Aclass%20Point%20%7B%0A%7D%0A%2F%2F%20%E7%AD%89%E5%90%8C%E4%BA%8E%20class%20Point%20%7B%0A%20%20constructor()%20%7B%7D%0A%7D%0A%60%60%60%0A%0Aconstructor%20%E6%96%B9%E6%B3%95%E9%BB%98%E8%AE%A4%E8%BF%94%E5%9B%9E%E5%AE%9E%E4%BE%8B%E5%AF%B9%E8%B1%A1(%E5%8D%B3%20this%20)%EF%BC%8C%E5%AE%8C%E5%85%A8%E5%8F%AF%E4%BB%A5%E6%8C%87%E5%AE%9A%E8%BF%94%E5%9B%9E%E5%8F%A6%E5%A4%96%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%E3%80%82%0A%60%60%60js%0Aclass%20Foo%20%7B%0A%20%20constructor()%20%7B%0A%20%20%20%20return%20Object.create(null)%3B%0A%20%20%7D%0A%7D%0Anew%20Foo()%20instanceof%20Foo%0A%2F%2F%20false%0A%0A%60%60%60%0A%0A%23%23%23%23%20%E7%B1%BB%E7%9A%84%E5%AE%9E%E4%BE%8B%E5%AF%B9%E8%B1%A1%0A%0A%E5%AE%9E%E4%BE%8B%E7%9A%84%E5%B1%9E%E6%80%A7%E9%99%A4%E9%9D%9E%E6%98%BE%E5%BC%8F%E5%AE%9A%E4%B9%89%E5%9C%A8%E5%85%B6%E6%9C%AC%E8%BA%AB(%E5%8D%B3%E5%AE%9A%E4%B9%89%E5%9C%A8%20this%20%E5%AF%B9%E8%B1%A1%20%E4%B8%8A)%EF%BC%8C%E5%90%A6%E5%88%99%E9%83%BD%E6%98%AF%E5%AE%9A%E4%B9%89%E5%9C%A8%E5%8E%9F%E5%9E%8B%E4%B8%8A(%E5%8D%B3%E5%AE%9A%E4%B9%89%E5%9C%A8%20class%20%E4%B8%8A)%E3%80%82%0A%60%60%60js%0A%2F%2F%E5%AE%9A%E4%B9%89%E7%B1%BB%0Aclass%20Point%20%7B%0A%20%20constructor(x%2C%20y)%20%7B%0A%20%20%20%20this.x%20%3D%20x%3B%0A%20%20%20%20this.y%20%3D%20y%3B%0A%7D%0A%20%20toString()%20%7B%0A%20%20%20%20return%20'('%20%2B%20this.x%20%2B%20'%2C%20'%20%2B%20this.y%20%2B%20')'%3B%0A%7D%20%7D%0Avar%20point%20%3D%20new%20Point(2%2C%203)%3B%0Apoint.toString()%20%2F%2F%20(2%2C%203)%0Apoint.hasOwnProperty('x')%20%2F%2F%20true%0Apoint.hasOwnProperty('y')%20%2F%2F%20true%0Apoint.hasOwnProperty('toString')%20%2F%2F%20false%0Apoint.__proto__.hasOwnProperty('toString')%20%2F%2F%20true%0A%60%60%60%0A%0A%E4%B8%8E%20ES5%20%E4%B8%80%E6%A0%B7%EF%BC%8C%E7%B1%BB%E7%9A%84%E6%89%80%E6%9C%89%E5%AE%9E%E4%BE%8B%E5%85%B1%E4%BA%AB%E4%B8%80%E4%B8%AA%E5%8E%9F%E5%9E%8B%E5%AF%B9%E8%B1%A1%E3%80%82%0A%0A%23%23%23%23%20Class%20%E8%A1%A8%E8%BE%BE%E5%BC%8F%0A%0A%E4%B8%8E%E5%87%BD%E6%95%B0%E4%B8%80%E6%A0%B7%EF%BC%8C%E7%B1%BB%E4%B9%9F%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9A%84%E5%BD%A2%E5%BC%8F%E5%AE%9A%E4%B9%89%E3%80%82%0A%60%60%60js%0Aconst%20MyClass%20%3D%20class%20Me%20%7B%0A%20%20getClassName()%20%7B%0A%20%20%20%20return%20Me.name%3B%0A%20%20%7D%0A%7D%3B%0A%0Alet%20inst%20%3D%20new%20MyClass()%3B%0Ainst.getClassName()%20%2F%2F%20Me%0AMe.name%20%2F%2F%20ReferenceError%3A%20Me%20is%20not%20defined%0A%60%60%60%0A%E9%9C%80%E8%A6%81%E6%B3%A8%E6%84%8F%E7%9A%84%E6%98%AF%EF%BC%8C%E8%BF%99%E4%B8%AA%E7%B1%BB%E7%9A%84%E5%90%8D%E5%AD%97%E6%98%AF%20MyClass%20%E8%80%8C%E4%B8%8D%E6%98%AF%20Me%20%EF%BC%8C%20Me%20%E5%8F%AA%E5%9C%A8%20Class%20%E7%9A%84%E5%86%85%E9%83%A8%E4%BB%A3%E7%A0%81%E5%8F%AF%E7%94%A8%EF%BC%8C%E6%8C%87%E4%BB%A3%E5%BD%93%E5%89%8D%E7%B1%BB%E3%80%82%0A%0A%23%23%23%23%20%E4%B8%8D%E5%AD%98%E5%9C%A8%E5%8F%98%E9%87%8F%E6%8F%90%E5%8D%87%0A%0A%E7%B1%BB%E4%B8%8D%E5%AD%98%E5%9C%A8%E5%8F%98%E9%87%8F%E6%8F%90%E5%8D%87(hoist)%0A%0A%23%23%23%23%20%E7%A7%81%E6%9C%89%E6%96%B9%E6%B3%95%0A%0A%E4%B8%80%E7%A7%8D%E5%81%9A%E6%B3%95%E6%98%AF%E5%9C%A8%E5%91%BD%E5%90%8D%E4%B8%8A%E5%8A%A0%E4%BB%A5%E5%8C%BA%E5%88%AB%E3%80%82%0A%60%60%60js%0Aclass%20Widget%20%7B%0A%2F%2F%20%E5%85%AC%E6%9C%89%E6%96%B9%E6%B3%95%0A%20%20foo%20(baz)%20%7B%0A%20%20%20%20this._bar(baz)%3B%0A%7D%0A%2F%2F%20%E7%A7%81%E6%9C%89%E6%96%B9%E6%B3%95%0A%20%20_bar(baz)%20%7B%0A%20%20%20%20return%20this.snaf%20%3D%20baz%3B%0A%7D%0A%2F%2F%20...%0A%7D%0A%60%60%60%0A%E4%BD%86%E6%98%AF%EF%BC%8C%E8%BF%99%E7%A7%8D%E5%91%BD%E5%90%8D%E6%98%AF%E4%B8%8D%E4%BF%9D%E9%99%A9%E7%9A%84%EF%BC%8C%E5%9C%A8%E7%B1%BB%E7%9A%84%E5%A4%96%E9%83%A8%EF%BC%8C%E8%BF%98%E6%98%AF%E5%8F%AF%E4%BB%A5%E8%B0%83%E7%94%A8%20%E5%88%B0%E8%BF%99%E4%B8%AA%E6%96%B9%E6%B3%95%E3%80%82%0A%0A%E5%8F%A6%E4%B8%80%E7%A7%8D%E6%96%B9%E6%B3%95%E5%B0%B1%E6%98%AF%E7%B4%A2%E6%80%A7%E5%B0%86%E7%A7%81%E6%9C%89%E6%96%B9%E6%B3%95%E7%A7%BB%E5%87%BA%E6%A8%A1%E5%9D%97%EF%BC%8C%E5%9B%A0%E4%B8%BA%E6%A8%A1%E5%9D%97%E5%86%85%E9%83%A8%E7%9A%84%E6%89%80%E6%9C%89%E6%96%B9%E6%B3%95%E9%83%BD%0A%E6%98%AF%E5%AF%B9%E5%A4%96%E5%8F%AF%E8%A7%81%E7%9A%84%E3%80%82%0A%60%60%60js%0Aclass%20Widget%20%7B%0A%20%20foo%20(baz)%20%7B%0A%20%20%20%20bar.call(this%2C%20baz)%3B%0A%20%20%7D%0A%2F%2F%20...%0A%7D%0Afunction%20bar(baz)%20%7B%0A%20%20return%20this.snaf%20%3D%20baz%3B%0A%7D%0A%60%60%60%0A%E4%B8%8A%E9%9D%A2%E4%BB%A3%E7%A0%81%E4%B8%AD%EF%BC%8C%20foo%20%E6%98%AF%E5%85%AC%E6%9C%89%E6%96%B9%E6%B3%95%EF%BC%8C%E5%86%85%E9%83%A8%E8%B0%83%E7%94%A8%E4%BA%86%20bar.call(this%2C%20baz)%20%E3%80%82%20%E8%BF%99%E4%BD%BF%E5%BE%97%20bar%20%E5%AE%9E%E9%99%85%E4%B8%8A%E6%88%90%E4%B8%BA%E4%BA%86%E5%BD%93%E5%89%8D%E6%A8%A1%E5%9D%97%E7%9A%84%E7%A7%81%E6%9C%89%E6%96%B9%E6%B3%95%E3%80%82%0A%0A%0A%E8%BF%98%E6%9C%89%E4%B8%80%E7%A7%8D%E6%96%B9%E6%B3%95%E6%98%AF%E5%88%A9%E7%94%A8%20Symbol%20%E5%80%BC%E7%9A%84%E5%94%AF%E4%B8%80%E6%80%A7%EF%BC%8C%E5%B0%86%E7%A7%81%E6%9C%89%E6%96%B9%E6%B3%95%E7%9A%84%E5%90%8D%E5%AD%97%E5%91%BD%E5%90%8D%E4%B8%BA%E4%B8%80%20%E4%B8%AA%20Symbol%20%E5%80%BC%E3%80%82%0A%60%60%60js%0Aconst%20bar%20%3D%20Symbol('bar')%3B%0Aconst%20snaf%20%3D%20Symbol('snaf')%3B%0Aexport%20default%20class%20myClass%7B%0A%2F%2F%20%E5%85%AC%E6%9C%89%E6%96%B9%E6%B3%95%0A%20%20foo(baz)%20%7B%0A%20%20%20%20this%5Bbar%5D(baz)%3B%0A%7D%0A%2F%2F%20%E7%A7%81%E6%9C%89%E6%96%B9%E6%B3%95%0A%20%20%5Bbar%5D(baz)%20%7B%0A%20%20%20%20return%20this%5Bsnaf%5D%20%3D%20baz%3B%0A%7D%0A%2F%2F%20...%0A%7D%3B%0A%60%60%60%0A%E4%B8%8A%E9%9D%A2%E4%BB%A3%E7%A0%81%E4%B8%AD%EF%BC%8C%20bar%20%E5%92%8C%20snaf%20%E9%83%BD%E6%98%AF%20Symbol%20%E5%80%BC%EF%BC%8C%E5%AF%BC%E8%87%B4%E7%AC%AC%E4%B8%89%E6%96%B9%E6%97%A0%E6%B3%95%E8%8E%B7%E5%8F%96%E5%88%B0%20%E5%AE%83%E4%BB%AC%EF%BC%8C%E5%9B%A0%E6%AD%A4%E8%BE%BE%E5%88%B0%E4%BA%86%E7%A7%81%E6%9C%89%E6%96%B9%E6%B3%95%E5%92%8C%E7%A7%81%E6%9C%89%E5%B1%9E%E6%80%A7%E7%9A%84%E6%95%88%E6%9E%9C%E3%80%82%0A%0A%23%23%23%23%20%E7%A7%81%E6%9C%89%E5%B1%9E%E6%80%A7%0A%0A%E4%B8%8E%E7%A7%81%E6%9C%89%E6%96%B9%E6%B3%95%E4%B8%80%E6%A0%B7%EF%BC%8CES6%20%E4%B8%8D%E6%94%AF%E6%8C%81%E7%A7%81%E6%9C%89%E5%B1%9E%E6%80%A7%E3%80%82%E7%9B%AE%E5%89%8D%EF%BC%8C%E6%9C%89%E4%B8%80%E4%B8%AA%E6%8F%90%E6%A1%88%EF%BC%8C%0A%E4%B8%BA%20class%20%E5%8A%A0%E4%BA%86%E7%A7%81%E6%9C%89%E5%B1%9E%E6%80%A7%E3%80%82%E6%96%B9%E6%B3%95%E6%98%AF%E5%9C%A8%E5%B1%9E%E6%80%A7%E5%90%8D%E4%B9%8B%E5%89%8D%EF%BC%8C%E4%BD%BF%E7%94%A8%20%23%20%E8%A1%A8%E7%A4%BA%E3%80%82%0A%60%60%60js%0Aclass%20Point%20%7B%0A%20%20%23x%3B%0Aconstructor(x%20%3D%200)%20%7B%0A%23x%20%3D%20%2Bx%3B%20%2F%2F%20%E5%86%99%E6%88%90%20this.%23x%20%E4%BA%A6%E5%8F%AF%0A%7D%0A%20%20get%20x()%20%7B%20return%20%23x%20%7D%0A%20%20set%20x(value)%20%7B%20%23x%20%3D%20%2Bvalue%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%20this%20%E7%9A%84%E6%8C%87%E5%90%91%0A%E7%B1%BB%E7%9A%84%E6%96%B9%E6%B3%95%E5%86%85%E9%83%A8%E5%A6%82%E6%9E%9C%E5%90%AB%E6%9C%89%20this%20%EF%BC%8C%E5%AE%83%E9%BB%98%E8%AE%A4%E6%8C%87%E5%90%91%E7%B1%BB%E7%9A%84%E5%AE%9E%E4%BE%8B%E3%80%82%E4%BD%86%E6%98%AF%EF%BC%8C%E5%BF%85%E9%A1%BB%E9%9D%9E%E5%B8%B8%0A%E5%B0%8F%E5%BF%83%EF%BC%8C%E4%B8%80%E6%97%A6%E5%8D%95%E7%8B%AC%E4%BD%BF%E7%94%A8%E8%AF%A5%E6%96%B9%E6%B3%95%EF%BC%8C%E5%BE%88%E5%8F%AF%E8%83%BD%E6%8A%A5%E9%94%99%E3%80%82%0A%60%60%60js%0Aclass%20Logger%20%7B%0A%20%20printName(name%20%3D%20'there')%20%7B%0A%20%20%20%20this.print(%60Hello%20%24%7Bname%7D%60)%3B%0A%20%20%7D%0A%20%20print(text)%20%7B%0A%20%20%20%20console.log(text)%3B%0A%7D%20%7D%0Aconst%20logger%20%3D%20new%20Logger()%3B%0Aconst%20%7B%20printName%20%7D%20%3D%20logger%3B%0AprintName()%3B%20%2F%2F%20TypeError%3A%20Cannot%20read%20property%20'print'%0Aof%20undefined%0A%60%60%60%0A%0A%E4%B8%80%E4%B8%AA%E6%AF%94%E8%BE%83%E7%AE%80%E5%8D%95%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95%E6%98%AF%EF%BC%8C%E5%9C%A8%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95%E4%B8%AD%E7%BB%91%E5%AE%9A%20this%20%EF%BC%8C%E8%BF%99%E6%A0%B7%E5%B0%B1%E4%B8%8D%E4%BC%9A%E6%89%BE%20%E4%B8%8D%E5%88%B0%20print%20%E6%96%B9%E6%B3%95%E4%BA%86%E3%80%82%0A%60%60%60js%0Aclass%20Logger%20%7B%0A%20%20constructor()%20%7B%0A%20%20%20%20this.printName%20%3D%20this.printName.bind(this)%3B%0A%20%20%7D%0A%2F%2F%20...%0A%7D%0A%60%60%60%0A%0A%E5%8F%A6%E4%B8%80%E7%A7%8D%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95%E6%98%AF%E4%BD%BF%E7%94%A8%E7%AE%AD%E5%A4%B4%E5%87%BD%E6%95%B0%E3%80%82%0A%60%60%60js%0Aclass%20Logger%20%7B%0A%20%20constructor()%20%7B%0A%20%20%20%20this.printName%20%3D%20(name%20%3D%20'there')%20%3D%3E%20%7B%0A%20%20%20%20%20%20this.print(%60Hello%20%24%7Bname%7D%60)%3B%0A%7D%3B%20%7D%0A%2F%2F%20...%0A%7D%0A%60%60%60%0A%0A%E8%BF%98%E6%9C%89%E4%B8%80%E7%A7%8D%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95%E6%98%AF%E4%BD%BF%E7%94%A8%20Proxy%20%EF%BC%8C%E8%8E%B7%E5%8F%96%E6%96%B9%E6%B3%95%E7%9A%84%E6%97%B6%E5%80%99%EF%BC%8C%E8%87%AA%E5%8A%A8%E7%BB%91%20%E5%AE%9A%20this%20%E3%80%82%0A%60%60%60js%0Afunction%20selfish%20(target)%20%7B%0A%20%20const%20cache%20%3D%20new%20WeakMap()%3B%0A%20%20const%20handler%20%3D%20%7B%0A%20%20%20%20get%20(target%2C%20key)%20%7B%0A%20%20%20%20%20%20const%20value%20%3D%20Reflect.get(target%2C%20key)%3B%0A%20%20%20%20%20%20if%20(typeof%20value%20!%3D%3D%20'function')%20%7B%0A%20%20%20%20%20%20%20%20return%20value%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20if%20(!cache.has(value))%20%7B%0A%20%20%20%20%20%20%20%20cache.set(value%2C%20value.bind(target))%3B%0A%7D%0A%20%20%20%20%20%20return%20cache.get(value)%3B%0A%20%20%20%20%7D%0A%20%20%7D%3B%0A%20%20const%20proxy%20%3D%20new%20Proxy(target%2C%20handler)%3B%0A%20%20return%20proxy%3B%0A%7D%0Aconst%20logger%20%3D%20selfish(new%20Logger())%3B%0A%60%60%60%0A%0A%23%23%23%23%20Class%20%E7%9A%84%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%0A%0A%E7%B1%BB%E7%9B%B8%E5%BD%93%E4%BA%8E%E5%AE%9E%E4%BE%8B%E7%9A%84%E5%8E%9F%E5%9E%8B%EF%BC%8C%E6%89%80%E6%9C%89%E5%9C%A8%E7%B1%BB%E4%B8%AD%E5%AE%9A%E4%B9%89%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E9%83%BD%E4%BC%9A%E8%A2%AB%E5%AE%9E%E4%BE%8B%E7%BB%A7%E6%89%BF%E3%80%82%E5%A6%82%E6%9E%9C%20%E5%9C%A8%E4%B8%80%E4%B8%AA%E6%96%B9%E6%B3%95%E5%89%8D%EF%BC%8C%E5%8A%A0%E4%B8%8A%20static%20%E5%85%B3%E9%94%AE%E5%AD%97%EF%BC%8C%E5%B0%B1%E8%A1%A8%E7%A4%BA%E8%AF%A5%E6%96%B9%E6%B3%95%E4%B8%8D%E4%BC%9A%E8%A2%AB%E5%AE%9E%E4%BE%8B%E7%BB%A7%E6%89%BF%EF%BC%8C%20%E8%80%8C%E6%98%AF%E7%9B%B4%E6%8E%A5%E9%80%9A%E8%BF%87%E7%B1%BB%E6%9D%A5%E8%B0%83%E7%94%A8%EF%BC%8C%E8%BF%99%E5%B0%B1%E7%A7%B0%E4%B8%BA%E2%80%9C%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%E2%80%9D%E3%80%82%0A%0A%60%60%60js%0Aclass%20Foo%20%7B%0A%20%20static%20classMethod()%20%7B%0A%20%20%20%20return%20'hello'%3B%0A%20%20%7D%0A%7D%0AFoo.classMethod()%20%2F%2F%20'hello'%0Avar%20foo%20%3D%20new%20Foo()%3B%0Afoo.classMethod()%0A%2F%2F%20TypeError%3A%20foo.classMethod%20is%20not%20a%20function%0A%60%60%60%0A%E6%B3%A8%E6%84%8F%EF%BC%8C%E5%A6%82%E6%9E%9C%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%E5%8C%85%E5%90%AB%20this%20%E5%85%B3%E9%94%AE%E5%AD%97%EF%BC%8C%E8%BF%99%E4%B8%AA%20this%20%E6%8C%87%E7%9A%84%E6%98%AF%E7%B1%BB%EF%BC%8C%E8%80%8C%E4%B8%8D%E6%98%AF%E5%AE%9E%E4%BE%8B%E3%80%82%0A%60%60%60js%0Aclass%20Foo%20%7B%0A%20%20static%20bar%20()%20%7B%0A%20%20%20%20this.baz()%3B%0A%20%20%7D%0A%20%20static%20baz%20()%20%7B%0A%20%20%20%20console.log('hello')%3B%0A%7D%0Abaz%20()%20%7B%0A%20%20%20%20console.log('world')%3B%0A%20%20%7D%0A%7D%0AFoo.bar()%20%2F%2F%20hello%0A%60%60%60%0A%0A%E4%BB%8E%E8%BF%99%E4%B8%AA%E4%BE%8B%E5%AD%90%E8%BF%98%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%87%BA%EF%BC%8C%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%E5%8F%AF%E4%BB%A5%E4%B8%8E%E9%9D%9E%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%E9%87%8D%E5%90%8D%E3%80%82%0A%E7%88%B6%E7%B1%BB%E7%9A%84%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%EF%BC%8C%E5%8F%AF%E4%BB%A5%E8%A2%AB%E5%AD%90%E7%B1%BB%E7%BB%A7%E6%89%BF%E3%80%82%0A%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%E4%B9%9F%E6%98%AF%E5%8F%AF%E4%BB%A5%E4%BB%8E%20super%20%E5%AF%B9%E8%B1%A1%E4%B8%8A%E8%B0%83%E7%94%A8%E7%9A%84%E3%80%82%0A%0A%23%23%23%23%20Class%20%E7%9A%84%E9%9D%99%E6%80%81%E5%B1%9E%E6%80%A7%E5%92%8C%E5%AE%9E%E4%BE%8B%E5%B1%9E%E6%80%A7%0A%E9%9D%99%E6%80%81%E5%B1%9E%E6%80%A7%E6%8C%87%E7%9A%84%E6%98%AF%20Class%20%E6%9C%AC%E8%BA%AB%E7%9A%84%E5%B1%9E%E6%80%A7%EF%BC%8C%E5%8D%B3%20Class.propName%20%EF%BC%8C%E8%80%8C%E4%B8%8D%E6%98%AF%E5%AE%9A%E4%B9%89%0A%E5%9C%A8%E5%AE%9E%E4%BE%8B%E5%AF%B9%E8%B1%A1(%20this%20)%E4%B8%8A%E7%9A%84%E5%B1%9E%E6%80%A7%E3%80%82%0A%60%60%60js%0Aclass%20Foo%20%7B%20%7D%0AFoo.prop%20%3D%201%3B%0AFoo.prop%20%2F%2F%201%0A%60%60%60%0A%E4%B8%8A%E9%9D%A2%E7%9A%84%E5%86%99%E6%B3%95%E4%B8%BA%20Foo%20%E7%B1%BB%E5%AE%9A%E4%B9%89%E4%BA%86%E4%B8%80%E4%B8%AA%E9%9D%99%E6%80%81%E5%B1%9E%E6%80%A7%20prop%20%E3%80%82%20%E7%9B%AE%E5%89%8D%EF%BC%8C%E5%8F%AA%E6%9C%89%E8%BF%99%E7%A7%8D%E5%86%99%E6%B3%95%E5%8F%AF%E8%A1%8C%EF%BC%8C%E5%9B%A0%E4%B8%BA%20ES6%20%E6%98%8E%E7%A1%AE%E8%A7%84%E5%AE%9A%EF%BC%8CClass%20%E5%86%85%E9%83%A8%E5%8F%AA%E6%9C%89%E9%9D%99%E6%80%81%E6%96%B9%0A%E6%B3%95%EF%BC%8C%E6%B2%A1%E6%9C%89%E9%9D%99%E6%80%81%E5%B1%9E%E6%80%A7%E3%80%82%0A%60%60%60js%0A%2F%2F%20%E4%BB%A5%E4%B8%8B%E4%B8%A4%E7%A7%8D%E5%86%99%E6%B3%95%E9%83%BD%E6%97%A0%E6%95%88%20class%20Foo%20%7B%0A%2F%2F%20%E5%86%99%E6%B3%95%E4%B8%80%0Aprop%3A%202%0A%2F%2F%20%E5%86%99%E6%B3%95%E4%BA%8C%0A%20%20static%20prop%3A%202%0A%7D%0AFoo.prop%20%2F%2F%20undefined%0A%60%60%60%0A%0A%23%23%23%23%20new.target%20%E5%B1%9E%E6%80%A7%0AES6%20%E4%B8%BA%20new%20%E5%91%BD%E4%BB%A4%E5%BC%95%E5%85%A5%E4%BA%86%E4%B8%80%20%E4%B8%AA%20new.target%20%E5%B1%9E%E6%80%A7%EF%BC%8C%E8%AF%A5%E5%B1%9E%E6%80%A7%E4%B8%80%E8%88%AC%E7%94%A8%E5%9C%A8%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E4%B9%8B%E4%B8%AD%EF%BC%8C%E8%BF%94%E5%9B%9E%20new%20%E5%91%BD%E4%BB%A4%20%E4%BD%9C%E7%94%A8%E4%BA%8E%E7%9A%84%E9%82%A3%E4%B8%AA%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E3%80%82%E5%A6%82%E6%9E%9C%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E4%B8%8D%E6%98%AF%E9%80%9A%E8%BF%87%20new%20%E5%91%BD%E4%BB%A4%E8%B0%83%E7%94%A8%E7%9A%84%EF%BC%8C%20new.target%20%E4%BC%9A%E8%BF%94%E5%9B%9E%20undefined%20%EF%BC%8C%E5%9B%A0%E6%AD%A4%E8%BF%99%E4%B8%AA%E5%B1%9E%E6%80%A7%E5%8F%AF%E4%BB%A5%E7%94%A8%E6%9D%A5%E7%A1%AE%E5%AE%9A%E6%9E%84%20%E9%80%A0%E5%87%BD%E6%95%B0%E6%98%AF%E6%80%8E%E4%B9%88%E8%B0%83%E7%94%A8%E7%9A%84%E3%80%82%0A%0A%60%60%60js%0Afunction%20Person(name)%20%7B%0A%20%20if%20(new.target%20!%3D%3D%20undefined)%20%7B%0A%20%20%20%20this.name%20%3D%20name%3B%0A%20%20%7D%20else%20%7B%0Athrow%20new%20Error('%E5%BF%85%E9%A1%BB%E4%BD%BF%E7%94%A8%20new%20%E5%91%BD%E4%BB%A4%E7%94%9F%E6%88%90%E5%AE%9E%E4%BE%8B')%3B%20%7D%0A%7D%0A%2F%2F%20%E5%8F%A6%E4%B8%80%E7%A7%8D%E5%86%99%E6%B3%95%0Afunction%20Person(name)%20%7B%0A%20%20if%20(new.target%20%3D%3D%3D%20Person)%20%7B%0A%20%20%20%20this.name%20%3D%20name%3B%0A%7D%20else%20%7B%0Athrow%20new%20Error('%E5%BF%85%E9%A1%BB%E4%BD%BF%E7%94%A8%20new%20%E5%91%BD%E4%BB%A4%E7%94%9F%E6%88%90%E5%AE%9E%E4%BE%8B')%3B%0A%7D%20%7D%0Avar%20person%20%3D%20new%20Person('%E5%BC%A0%E4%B8%89')%3B%20%2F%2F%20%E6%AD%A3%E7%A1%AE%0Avar%20notAPerson%20%3D%20Person.call(person%2C%20'%E5%BC%A0%E4%B8%89')%3B%20%2F%2F%20%E6%8A%A5%E9%94%99%0A%60%60%60%0A%0AClass%20%E5%86%85%E9%83%A8%E8%B0%83%E7%94%A8%20new.target%20%EF%BC%8C%E8%BF%94%E5%9B%9E%E5%BD%93%E5%89%8D%20Class%E3%80%82%0A%E9%9C%80%E8%A6%81%E6%B3%A8%E6%84%8F%E7%9A%84%E6%98%AF%EF%BC%8C%E5%AD%90%E7%B1%BB%E7%BB%A7%E6%89%BF%E7%88%B6%E7%B1%BB%E6%97%B6%EF%BC%8C%20new.target%20%E4%BC%9A%E8%BF%94%E5%9B%9E%E5%AD%90%E7%B1%BB%E3%80%82%0A%0A%23%23%20Class%20%E7%9A%84%E7%BB%A7%E6%89%BF%0A%0AClass%20%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%20extends%20%E5%85%B3%E9%94%AE%E5%AD%97%E5%AE%9E%E7%8E%B0%E7%BB%A7%E6%89%BF%0A%60%60%60js%0Aclass%20Point%20%7B%0A%7D%0Aclass%20ColorPoint%20extends%20Point%20%7B%0A%7D%0A%60%60%60%0A%E5%AD%90%E7%B1%BB%E5%BF%85%E9%A1%BB%E5%9C%A8%20constructor%20%E6%96%B9%E6%B3%95%E4%B8%AD%E8%B0%83%E7%94%A8%20super%20%E6%96%B9%E6%B3%95%EF%BC%8C%E5%90%A6%E5%88%99%E6%96%B0%E5%BB%BA%E5%AE%9E%E4%BE%8B%E6%97%B6%E4%BC%9A%20%E6%8A%A5%E9%94%99%E3%80%82%E8%BF%99%E6%98%AF%E5%9B%A0%E4%B8%BA%E5%AD%90%E7%B1%BB%E6%B2%A1%E6%9C%89%E8%87%AA%E5%B7%B1%E7%9A%84%20this%20%E5%AF%B9%E8%B1%A1%EF%BC%8C%E8%80%8C%E6%98%AF%E7%BB%A7%E6%89%BF%E7%88%B6%E7%B1%BB%E7%9A%84%20this%20%E5%AF%B9%20%E8%B1%A1%EF%BC%8C%E7%84%B6%E5%90%8E%E5%AF%B9%E5%85%B6%E8%BF%9B%E8%A1%8C%E5%8A%A0%E5%B7%A5%E3%80%82%E5%A6%82%E6%9E%9C%E4%B8%8D%E8%B0%83%E7%94%A8%20super%20%E6%96%B9%E6%B3%95%EF%BC%8C%E5%AD%90%E7%B1%BB%E5%B0%B1%E5%BE%97%E4%B8%8D%0A%E5%88%B0%20this%20%E5%AF%B9%E8%B1%A1%E3%80%82%0A%60%60%60js%0Aclass%20Point%20%7B%20%2F*%20...%20*%2F%20%7D%0Aclass%20ColorPoint%20extends%20Point%20%7B%0A%20%20constructor()%20%7B%0A%20%20%7D%0A%7D%0Alet%20cp%20%3D%20new%20ColorPoint()%3B%20%2F%2F%20ReferenceError%0A%60%60%60%0A%0AES6%20%E7%9A%84%E7%BB%A7%E6%89%BF%E6%9C%BA%E5%88%B6%E5%AE%8C%E5%85%A8%EF%BC%8C%E5%AE%9E%E8%B4%A8%E6%98%AF%E5%85%88%E5%88%9B%E9%80%A0%E7%88%B6%E7%B1%BB%E7%9A%84%E5%AE%9E%E4%BE%8B%E5%AF%B9%E8%B1%A1%20this%20(%E6%89%80%E4%BB%A5%E5%BF%85%E9%A1%BB%E5%85%88%E8%B0%83%0A%E7%94%A8%20super%20%E6%96%B9%E6%B3%95)%EF%BC%8C%E7%84%B6%E5%90%8E%E5%86%8D%E7%94%A8%E5%AD%90%E7%B1%BB%E7%9A%84%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E4%BF%AE%E6%94%B9%20this%20%E3%80%82%0A%E5%A6%82%E6%9E%9C%E5%AD%90%E7%B1%BB%E6%B2%A1%E6%9C%89%E5%AE%9A%E4%B9%89%20constructor%20%E6%96%B9%E6%B3%95%EF%BC%8C%E8%BF%99%E4%B8%AA%E6%96%B9%E6%B3%95%E4%BC%9A%E8%A2%AB%E9%BB%98%E8%AE%A4%E6%B7%BB%E5%8A%A0%EF%BC%8C%E4%BB%A3%E7%A0%81%20%E5%A6%82%E4%B8%8B%E3%80%82%0A%60%60%60js%0Aclass%20ColorPoint%20extends%20Point%20%7B%0A%7D%0A%2F%2F%20%E7%AD%89%E5%90%8C%E4%BA%8E%0Aclass%20ColorPoint%20extends%20Point%20%7B%0A%20%20constructor(...args)%20%7B%0A%20%20%20%20super(...args)%3B%0A%7D%20%7D%0A%60%60%60%0A%0A%E5%8F%A6%E4%B8%80%E4%B8%AA%E9%9C%80%E8%A6%81%E6%B3%A8%E6%84%8F%E7%9A%84%E5%9C%B0%E6%96%B9%E6%98%AF%EF%BC%8C%E5%9C%A8%E5%AD%90%E7%B1%BB%E7%9A%84%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E4%B8%AD%EF%BC%8C%E5%8F%AA%E6%9C%89%E8%B0%83%E7%94%A8%20super%20%E4%B9%8B%20%E5%90%8E%EF%BC%8C%E6%89%8D%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%20this%20%E5%85%B3%E9%94%AE%E5%AD%97%EF%BC%8C%E5%90%A6%E5%88%99%E4%BC%9A%E6%8A%A5%E9%94%99%E3%80%82%E8%BF%99%E6%98%AF%E5%9B%A0%E4%B8%BA%E5%AD%90%E7%B1%BB%E5%AE%9E%E4%BE%8B%E7%9A%84%E6%9E%84%20%E5%BB%BA%EF%BC%8C%E6%98%AF%E5%9F%BA%E4%BA%8E%E5%AF%B9%E7%88%B6%E7%B1%BB%E5%AE%9E%E4%BE%8B%E5%8A%A0%E5%B7%A5%EF%BC%8C%E5%8F%AA%E6%9C%89%20super%20%E6%96%B9%E6%B3%95%E6%89%8D%E8%83%BD%E8%BF%94%E5%9B%9E%E7%88%B6%E7%B1%BB%E5%AE%9E%E4%BE%8B%E3%80%82%0A%0A%23%23%23%23%20%E7%B1%BB%E7%9A%84%20prototype%20%E5%B1%9E%E6%80%A7%E5%92%8C__proto__%E5%B1%9E%E6%80%A7%0A%0A(1)%E5%AD%90%E7%B1%BB%E7%9A%84%20__proto__%20%E5%B1%9E%E6%80%A7%EF%BC%8C%E8%A1%A8%E7%A4%BA%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E7%9A%84%E7%BB%A7%E6%89%BF%EF%BC%8C%E6%80%BB%E6%98%AF%E6%8C%87%E5%90%91%E7%88%B6%E7%B1%BB%E3%80%82%20(2)%E5%AD%90%E7%B1%BB%20prototype%20%E5%B1%9E%E6%80%A7%E7%9A%84%20__proto__%20%E5%B1%9E%E6%80%A7%EF%BC%8C%E8%A1%A8%E7%A4%BA%E6%96%B9%E6%B3%95%E7%9A%84%E7%BB%A7%E6%89%BF%EF%BC%8C%E6%80%BB%0A%E6%98%AF%E6%8C%87%E5%90%91%E7%88%B6%E7%B1%BB%E7%9A%84%20prototype%20%E5%B1%9E%E6%80%A7%E3%80%82%0A%60%60%60js%0Aclass%20A%20%7B%20%7D%0Aclass%20B%20extends%20A%20%7B%0A%7D%0AB.__proto__%20%3D%3D%3D%20A%20%2F%2F%20true%0AB.prototype.__proto__%20%3D%3D%3D%20A.prototype%20%2F%2F%20true%0A%0A%2F%2F%E7%B1%BB%E7%9A%84%E7%BB%A7%E6%89%BF%E6%98%AF%E6%8C%89%E7%85%A7%E4%B8%8B%E9%9D%A2%E7%9A%84%E6%A8%A1%E5%BC%8F%E5%AE%9E%E7%8E%B0%E7%9A%84%0Aclass%20A%20%7B%20%7D%0Aclass%20B%20%7B%20%7D%0A%2F%2F%20B%20%E7%9A%84%E5%AE%9E%E4%BE%8B%E7%BB%A7%E6%89%BF%20A%20%E7%9A%84%E5%AE%9E%E4%BE%8B%0AObject.setPrototypeOf(B.prototype%2C%20A.prototype)%3B%20%2F%2F%20B%20%E7%9A%84%E5%AE%9E%E4%BE%8B%E7%BB%A7%E6%89%BF%20A%20%E7%9A%84%E9%9D%99%E6%80%81%E5%B1%9E%E6%80%A7%0AObject.setPrototypeOf(B%2C%20A)%3B%0Aconst%20b%20%3D%20new%20B()%3B%0A%0AObject.setPrototypeOf(B.prototype%2C%20A.prototype)%3B%20%2F%2F%20%E7%AD%89%E5%90%8C%E4%BA%8E%0AB.prototype.__proto__%20%3D%20A.prototype%3B%0AObject.setPrototypeOf(B%2C%20A)%3B%20%2F%2F%20%E7%AD%89%E5%90%8C%E4%BA%8E%0AB.__proto__%20%3D%20A%3B%0A%60%60%60%0A%0A%23%23%23%23%20extends%20%E7%9A%84%E7%BB%A7%E6%89%BF%E7%9B%AE%E6%A0%87%0A%60%60%60js%0Aclass%20B%20extends%20A%20%7B%0A%7D%0A%0A%2F%2F%E4%B8%8A%E9%9D%A2%E4%BB%A3%E7%A0%81%E7%9A%84%20A%20%EF%BC%8C%E5%8F%AA%E8%A6%81%E6%98%AF%E4%B8%80%E4%B8%AA%E6%9C%89%20prototype%20%E5%B1%9E%E6%80%A7%E7%9A%84%E5%87%BD%E6%95%B0%EF%BC%8C%E5%B0%B1%E8%83%BD%E8%A2%AB%20B%20%E7%BB%A7%20%E6%89%BF%E3%80%82%E7%94%B1%E4%BA%8E%E5%87%BD%E6%95%B0%E9%83%BD%E6%9C%89%20prototype%20%E5%B1%9E%E6%80%A7(%E9%99%A4%E4%BA%86%20Function.prototype%20%E5%87%BD%20%E6%95%B0)%EF%BC%8C%E5%9B%A0%E6%AD%A4%20A%20%E5%8F%AF%E4%BB%A5%E6%98%AF%E4%BB%BB%E6%84%8F%E5%87%BD%E6%95%B0%E3%80%82%0A%0A%2F%2F%E4%B8%8B%E9%9D%A2%EF%BC%8C%E8%AE%A8%E8%AE%BA%E4%B8%89%E7%A7%8D%E7%89%B9%E6%AE%8A%E6%83%85%E5%86%B5%E3%80%82%0A%2F%2F%E7%AC%AC%E4%B8%80%E7%A7%8D%E7%89%B9%E6%AE%8A%E6%83%85%E5%86%B5%EF%BC%8C%E5%AD%90%E7%B1%BB%E7%BB%A7%E6%89%BF%20Object%20%E7%B1%BB%E3%80%82%0Aclass%20A%20extends%20Object%20%7B%0A%7D%0AA.__proto__%20%3D%3D%3D%20Object%20%2F%2F%20true%0AA.prototype.__proto__%20%3D%3D%3D%20Object.prototype%20%2F%2F%20true%0A%0A%2F%2F%E7%AC%AC%E4%BA%8C%E7%A7%8D%E7%89%B9%E6%AE%8A%E6%83%85%E5%86%B5%EF%BC%8C%E4%B8%8D%E5%AD%98%E5%9C%A8%E4%BB%BB%E4%BD%95%E7%BB%A7%E6%89%BF%E3%80%82%0Aclass%20A%20%7B%20%7D%0AA.__proto__%20%3D%3D%3D%20Function.prototype%20%2F%2F%20true%0AA.prototype.__proto__%20%3D%3D%3D%20Object.prototype%20%2F%2F%20true%0A%0A%2F%2F%E7%AC%AC%E4%B8%89%E7%A7%8D%E7%89%B9%E6%AE%8A%E6%83%85%E5%86%B5%EF%BC%8C%E5%AD%90%E7%B1%BB%E7%BB%A7%E6%89%BF%20null%20%E3%80%82%0Aclass%20A%20extends%20null%20%7B%0A%7D%0AA.__proto__%20%3D%3D%3D%20Function.prototype%20%2F%2F%20true%0AA.prototype.__proto__%20%3D%3D%3D%20undefined%20%2F%2F%20true%0A%60%60%60%0A%0A%23%23%23%23%20%E5%AE%9E%E4%BE%8B%E7%9A%84%20__proto__%20%E5%B1%9E%E6%80%A7%0A%E5%AD%90%E7%B1%BB%E5%AE%9E%E4%BE%8B%E7%9A%84%20__proto__%20%E5%B1%9E%E6%80%A7%E7%9A%84%20__proto__%20%E5%B1%9E%E6%80%A7%EF%BC%8C%E6%8C%87%E5%90%91%E7%88%B6%E7%B1%BB%E5%AE%9E%E4%BE%8B%0A%E7%9A%84%20__proto__%20%E5%B1%9E%E6%80%A7%E3%80%82%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%EF%BC%8C%E5%AD%90%E7%B1%BB%E7%9A%84%E5%8E%9F%E5%9E%8B%E7%9A%84%E5%8E%9F%E5%9E%8B%EF%BC%8C%E6%98%AF%E7%88%B6%E7%B1%BB%E7%9A%84%E5%8E%9F%E5%9E%8B%E3%80%82%0A%60%60%60js%0Avar%20p1%20%3D%20new%20Point(2%2C%203)%3B%0Avar%20p2%20%3D%20new%20ColorPoint(2%2C%203%2C%20'red')%3B%0Ap2.__proto__%20%3D%3D%3D%20p1.__proto__%20%2F%2F%20false%0Ap2.__proto__.__proto__%20%3D%3D%3D%20p1.__proto__%20%2F%2F%20true%0A%60%60%60%0A%0A%20extends%20%E5%85%B3%E9%94%AE%E5%AD%97%E4%B8%8D%E4%BB%85%E5%8F%AF%E4%BB%A5%E7%94%A8%E6%9D%A5%E7%BB%A7%E6%89%BF%E7%B1%BB%EF%BC%8C%E8%BF%98%E5%8F%AF%E4%BB%A5%20%E7%94%A8%E6%9D%A5%E7%BB%A7%E6%89%BF%E5%8E%9F%E7%94%9F%E7%9A%84%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E3%80%82%0A%0A%0A%23%23%23%23%20%E5%8E%9F%E7%94%9F%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E7%9A%84%E7%BB%A7%E6%89%BF%0AECMAScript%20%E7%9A%84%E5%8E%9F%E7%94%9F%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E5%A4%A7%E8%87%B4%E6%9C%89%E4%B8%8B%E9%9D%A2%E8%BF%99%E4%BA%9B%EF%BC%9A%0ABoolean()%20%0ANumber()%20%0AString()%20%0AArray()%20%0ADate()%20%0AFunction()%20%0ARegExp()%20%0AError()%20%0AObject()%0A%0A%E4%BB%A5%E5%89%8D%EF%BC%8C%E8%BF%99%E4%BA%9B%E5%8E%9F%E7%94%9F%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E6%98%AF%E6%97%A0%E6%B3%95%E7%BB%A7%E6%89%BF%E7%9A%84%E3%80%82%E5%9B%A0%E4%B8%BA%E5%AD%90%E7%B1%BB%E6%97%A0%E6%B3%95%E8%8E%B7%E5%BE%97%E5%8E%9F%E7%94%9F%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E7%9A%84%E5%86%85%E9%83%A8%E5%B1%9E%20%E6%80%A7%EF%BC%8C%E9%80%9A%E8%BF%87%20Array.apply()%20%E6%88%96%E8%80%85%E5%88%86%E9%85%8D%E7%BB%99%E5%8E%9F%E5%9E%8B%E5%AF%B9%E8%B1%A1%E9%83%BD%E4%B8%8D%E8%A1%8C%E3%80%82%E5%8E%9F%E7%94%9F%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%20%E4%BC%9A%E5%BF%BD%E7%95%A5%20apply%20%E6%96%B9%E6%B3%95%E4%BC%A0%E5%85%A5%E7%9A%84%20this%20%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%EF%BC%8C%E5%8E%9F%E7%94%9F%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E7%9A%84%20this%20%E6%97%A0%E6%B3%95%E7%BB%91%E5%AE%9A%EF%BC%8C%E5%AF%BC%E8%87%B4%E6%8B%BF%E4%B8%8D%E5%88%B0%E5%86%85%E9%83%A8%E5%B1%9E%E6%80%A7%E3%80%82%0A%0AES6%20%E5%85%81%E8%AE%B8%E7%BB%A7%E6%89%BF%E5%8E%9F%E7%94%9F%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E5%AE%9A%E4%B9%89%E5%AD%90%E7%B1%BB%EF%BC%8C%E5%9B%A0%E4%B8%BA%20ES6%20%E6%98%AF%E5%85%88%E6%96%B0%E5%BB%BA%E7%88%B6%E7%B1%BB%E7%9A%84%E5%AE%9E%E4%BE%8B%E5%AF%B9%20%E8%B1%A1%20this%20%EF%BC%8C%E7%84%B6%E5%90%8E%E5%86%8D%E7%94%A8%E5%AD%90%E7%B1%BB%E7%9A%84%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E4%BF%AE%E9%A5%B0%20this%20%EF%BC%8C%E4%BD%BF%E5%BE%97%E7%88%B6%E7%B1%BB%E7%9A%84%E6%89%80%E6%9C%89%E8%A1%8C%E4%B8%BA%20%E9%83%BD%E5%8F%AF%E4%BB%A5%E7%BB%A7%E6%89%BF%E3%80%82%0A%0A%E6%B3%A8%E6%84%8F%EF%BC%8C%E7%BB%A7%E6%89%BF%20Object%20%E7%9A%84%E5%AD%90%E7%B1%BB%EF%BC%8C%E6%9C%89%E4%B8%80%E4%B8%AA%E8%A1%8C%E4%B8%BA%E5%B7%AE%E5%BC%82%E3%80%82%0A%0A%60%60%60js%0Aclass%20NewObj%20extends%20Object%7B%0A%20%20constructor()%7B%0A%20%20%20%20super(...arguments)%3B%0A%20%20%7D%0A%7D%0Avar%20o%20%3D%20new%20NewObj(%7Battr%3A%20true%7D)%3B%0Ao.attr%20%3D%3D%3D%20true%20%20%2F%2F%20false%0A%60%60%60%0A%0A%E8%BF%99%E6%98%AF%E5%9B%A0%E4%B8%BA%20ES6%20%E6%94%B9%E5%8F%98%E4%BA%86%20Object%20%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E7%9A%84%E8%A1%8C%E4%B8%BA%EF%BC%8C%E4%B8%80%20%E6%97%A6%E5%8F%91%E7%8E%B0%20Object%20%E6%96%B9%E6%B3%95%E4%B8%8D%E6%98%AF%E9%80%9A%E8%BF%87%20new%20Object()%20%E8%BF%99%E7%A7%8D%E5%BD%A2%E5%BC%8F%E8%B0%83%E7%94%A8%EF%BC%8CES6%20%E8%A7%84%20%E5%AE%9A%20Object%20%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E4%BC%9A%E5%BF%BD%E7%95%A5%E5%8F%82%E6%95%B0%E3%80%82%0A%0A%23%23%20Module%20%E7%9A%84%E8%AF%AD%E6%B3%95%0A%0AES6%20%E6%A8%A1%E5%9D%97%E7%9A%84%E8%AE%BE%E8%AE%A1%E6%80%9D%E6%83%B3%EF%BC%8C%E6%98%AF%E5%B0%BD%E9%87%8F%E7%9A%84%E9%9D%99%E6%80%81%E5%8C%96%EF%BC%8C%E4%BD%BF%E5%BE%97%E7%BC%96%E8%AF%91%E6%97%B6%E5%B0%B1%E8%83%BD%E7%A1%AE%E5%AE%9A%E6%A8%A1%E5%9D%97%E7%9A%84%E4%BE%9D%20%E8%B5%96%E5%85%B3%E7%B3%BB%EF%BC%8C%E4%BB%A5%E5%8F%8A%E8%BE%93%E5%85%A5%E5%92%8C%E8%BE%93%E5%87%BA%E7%9A%84%E5%8F%98%E9%87%8F%0A%0A%60%60%60js%0A%2F%2F%20CommonJS%E6%A8%A1%E5%9D%97%0Alet%20%7B%20stat%2C%20exists%2C%20readFile%20%7D%20%3D%20require('fs')%3B%0A%2F%2F%20%E7%AD%89%E5%90%8C%E4%BA%8E%0Alet%20_fs%20%3D%20require('fs')%3B%0Alet%20stat%20%3D%20_fs.stat%3B%0Alet%20exists%20%3D%20_fs.exists%3B%0Alet%20readfile%20%3D%20_fs.readfile%3B%0A%0A%2F%2F%20ES6%E6%A8%A1%E5%9D%97%0Aimport%20%7B%20stat%2C%20exists%2C%20readFile%20%7D%20from%20'fs'%3B%0A%60%60%60%0A%0A%E7%94%B1%E4%BA%8E%20ES6%20%E6%A8%A1%E5%9D%97%E6%98%AF%E7%BC%96%E8%AF%91%E6%97%B6%E5%8A%A0%E8%BD%BD%EF%BC%8C%E4%BD%BF%E5%BE%97%E9%9D%99%E6%80%81%E5%88%86%E6%9E%90%E6%88%90%E4%B8%BA%E5%8F%AF%E8%83%BD%E3%80%82%E6%9C%89%E4%BA%86%E5%AE%83%EF%BC%8C%E5%B0%B1%E8%83%BD%E8%BF%9B%20%E4%B8%80%E6%AD%A5%E6%8B%93%E5%AE%BD%20JavaScript%20%E7%9A%84%E8%AF%AD%E6%B3%95%EF%BC%8C%E6%AF%94%E5%A6%82%E5%BC%95%E5%85%A5%E5%AE%8F(macro)%E5%92%8C%E7%B1%BB%E5%9E%8B%E6%A3%80%E9%AA%8C(type%20system)%E8%BF%99%E4%BA%9B%E5%8F%AA%E8%83%BD%E9%9D%A0%E9%9D%99%E6%80%81%E5%88%86%E6%9E%90%E5%AE%9E%E7%8E%B0%E7%9A%84%E5%8A%9F%E8%83%BD%E3%80%82%0A%E9%99%A4%E4%BA%86%E9%9D%99%E6%80%81%E5%8A%A0%E8%BD%BD%E5%B8%A6%E6%9D%A5%E7%9A%84%E5%90%84%E7%A7%8D%E5%A5%BD%E5%A4%84%EF%BC%8CES6%20%E6%A8%A1%E5%9D%97%E8%BF%98%E6%9C%89%E4%BB%A5%E4%B8%8B%E5%A5%BD%E5%A4%84%E3%80%82%0A%E4%B8%8D%E5%86%8D%E9%9C%80%E8%A6%81%20UMD%20%E6%A8%A1%E5%9D%97%E6%A0%BC%E5%BC%8F%E4%BA%86%EF%BC%8C%E5%B0%86%E6%9D%A5%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%92%8C%E6%B5%8F%E8%A7%88%E5%99%A8%E9%83%BD%E4%BC%9A%E6%94%AF%E6%8C%81%20ES6%20%E6%A8%A1%E5%9D%97%20%E6%A0%BC%E5%BC%8F%E3%80%82%E7%9B%AE%E5%89%8D%EF%BC%8C%E9%80%9A%E8%BF%87%E5%90%84%E7%A7%8D%E5%B7%A5%E5%85%B7%E5%BA%93%EF%BC%8C%E5%85%B6%E5%AE%9E%E5%B7%B2%E7%BB%8F%E5%81%9A%E5%88%B0%E4%BA%86%E8%BF%99%E4%B8%80%E7%82%B9%E3%80%82%0A%E5%B0%86%E6%9D%A5%E6%B5%8F%E8%A7%88%E5%99%A8%E7%9A%84%E6%96%B0%20API%20%E5%B0%B1%E8%83%BD%E7%94%A8%E6%A8%A1%E5%9D%97%E6%A0%BC%E5%BC%8F%E6%8F%90%E4%BE%9B%EF%BC%8C%E4%B8%8D%E5%86%8D%E5%BF%85%E9%A1%BB%E5%81%9A%E6%88%90%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F%20%E6%88%96%E8%80%85%20navigator%20%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%B1%9E%E6%80%A7%E3%80%82%0A%E4%B8%8D%E5%86%8D%E9%9C%80%E8%A6%81%E5%AF%B9%E8%B1%A1%E4%BD%9C%E4%B8%BA%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4(%E6%AF%94%E5%A6%82%20Math%20%E5%AF%B9%E8%B1%A1)%EF%BC%8C%E6%9C%AA%E6%9D%A5%E8%BF%99%E4%BA%9B%E5%8A%9F%E8%83%BD%E5%8F%AF%20%E4%BB%A5%E9%80%9A%E8%BF%87%E6%A8%A1%E5%9D%97%E6%8F%90%E4%BE%9B%E3%80%82%0A%0A%23%23%23%23%20%E4%B8%A5%E6%A0%BC%E6%A8%A1%E5%BC%8F%0A%0AES6%20%E7%9A%84%E6%A8%A1%E5%9D%97%E8%87%AA%E5%8A%A8%E9%87%87%E7%94%A8%E4%B8%A5%E6%A0%BC%E6%A8%A1%E5%BC%8F%EF%BC%8C%E4%B8%8D%E7%AE%A1%E4%BD%A0%E6%9C%89%E6%B2%A1%E6%9C%89%E5%9C%A8%E6%A8%A1%E5%9D%97%E5%A4%B4%E9%83%A8%E5%8A%A0%E4%B8%8A%20%22use%0Astrict%22%3B%20%E3%80%82%0A%0A%23%23%23%23%20export%20%E5%91%BD%E4%BB%A4%0A%E6%A8%A1%E5%9D%97%E5%8A%9F%E8%83%BD%E4%B8%BB%E8%A6%81%E7%94%B1%E4%B8%A4%E4%B8%AA%E5%91%BD%E4%BB%A4%E6%9E%84%E6%88%90%3A%20export%20%E5%92%8C%20import%20%E3%80%82%20export%20%E5%91%BD%E4%BB%A4%E7%94%A8%0A%E4%BA%8E%E8%A7%84%E5%AE%9A%E6%A8%A1%E5%9D%97%E7%9A%84%E5%AF%B9%E5%A4%96%E6%8E%A5%E5%8F%A3%EF%BC%8C%20import%20%E5%91%BD%E4%BB%A4%E7%94%A8%E4%BA%8E%E8%BE%93%E5%85%A5%E5%85%B6%E4%BB%96%E6%A8%A1%E5%9D%97%E6%8F%90%E4%BE%9B%E7%9A%84%E5%8A%9F%E8%83%BD%E3%80%82%0A%0A%60%60%60js%0A%2F%2F%20profile.js%0Aexport%20var%20firstName%20%3D%20'Michael'%3B%0Aexport%20var%20lastName%20%3D%20'Jackson'%3B%0Aexport%20var%20year%20%3D%201958%3B%0A%0A%2F%2F%20profile.js%0Avar%20firstName%20%3D%20'Michael'%3B%0Avar%20lastName%20%3D%20'Jackson'%3B%0Avar%20year%20%3D%201958%3B%0Aexport%20%7BfirstName%2C%20lastName%2C%20year%7D%3B%0A%0A%2F%2Fexport%20%E5%91%BD%E4%BB%A4%E9%99%A4%E4%BA%86%E8%BE%93%E5%87%BA%E5%8F%98%E9%87%8F%EF%BC%8C%E8%BF%98%E5%8F%AF%E4%BB%A5%E8%BE%93%E5%87%BA%E5%87%BD%E6%95%B0%E6%88%96%E7%B1%BB(class)%E3%80%82%0Aexport%20function%20multiply(x%2C%20y)%20%7B%0A%20%20return%20x%20*%20y%3B%0A%7D%3B%0A%60%60%60%0A%0A%E9%80%9A%E5%B8%B8%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%20export%20%E8%BE%93%E5%87%BA%E7%9A%84%E5%8F%98%E9%87%8F%E5%B0%B1%E6%98%AF%E6%9C%AC%E6%9D%A5%E7%9A%84%E5%90%8D%E5%AD%97%EF%BC%8C%E4%BD%86%E6%98%AF%E5%8F%AF%E4%BB%A5%E4%BD%BF%0A%E7%94%A8%20as%20%E5%85%B3%E9%94%AE%E5%AD%97%E9%87%8D%E5%91%BD%E5%90%8D%E3%80%82%0A%60%60%60js%0Afunction%20v1()%20%7B%20...%20%7D%0Afunction%20v2()%20%7B%20...%20%7D%0Aexport%20%7B%0A%20%20v1%20as%20streamV1%2C%0A%20%20v2%20as%20streamV2%2C%0A%20%20v2%20as%20streamLatestVersion%0A%7D%3B%0A%60%60%60%0A%0A%E9%9C%80%E8%A6%81%E7%89%B9%E5%88%AB%E6%B3%A8%E6%84%8F%E7%9A%84%E6%98%AF%EF%BC%8C%20export%20%E5%91%BD%E4%BB%A4%E8%A7%84%E5%AE%9A%E7%9A%84%E6%98%AF%E5%AF%B9%E5%A4%96%E7%9A%84%E6%8E%A5%E5%8F%A3%EF%BC%8C%E5%BF%85%E9%A1%BB%E4%B8%8E%E6%A8%A1%E5%9D%97%E5%86%85%20%E9%83%A8%E7%9A%84%E5%8F%98%E9%87%8F%E5%BB%BA%E7%AB%8B%E4%B8%80%E4%B8%80%E5%AF%B9%E5%BA%94%E5%85%B3%E7%B3%BB%E3%80%82%0A%60%60%60js%0A%2F%2F%20%E6%8A%A5%E9%94%99%0Aexport%201%3B%0A%2F%2F%20%E6%8A%A5%E9%94%99%0Avar%20m%20%3D%201%3B%0Aexport%20m%3B%0A%0A%2F%2F%E6%AD%A3%E7%A1%AE%E7%9A%84%E5%86%99%E6%B3%95%E6%98%AF%E4%B8%8B%E9%9D%A2%E8%BF%99%E6%A0%B7%0A%2F%2F%20%E5%86%99%E6%B3%95%E4%B8%80%0Aexport%20var%20m%20%3D%201%3B%0A%2F%2F%20%E5%86%99%E6%B3%95%E4%BA%8C%0Avar%20m%20%3D%201%3B%0Aexport%20%7Bm%7D%3B%0A%2F%2F%20%E5%86%99%E6%B3%95%E4%B8%89%0Avar%20n%20%3D%201%3B%0Aexport%20%7Bn%20as%20m%7D%3B%0A%60%60%60%0A%0A%E5%8F%A6%E5%A4%96%EF%BC%8C%20export%20%E8%AF%AD%E5%8F%A5%E8%BE%93%E5%87%BA%E7%9A%84%E6%8E%A5%E5%8F%A3%EF%BC%8C%E4%B8%8E%E5%85%B6%E5%AF%B9%E5%BA%94%E7%9A%84%E5%80%BC%E6%98%AF%E5%8A%A8%E6%80%81%E7%BB%91%E5%AE%9A%E5%85%B3%E7%B3%BB%EF%BC%8C%E5%8D%B3%E9%80%9A%20%E8%BF%87%E8%AF%A5%E6%8E%A5%E5%8F%A3%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%8F%96%E5%88%B0%E6%A8%A1%E5%9D%97%E5%86%85%E9%83%A8%E5%AE%9E%E6%97%B6%E7%9A%84%E5%80%BC%E3%80%82%0A%0A%23%23%23%23%20import%20%E5%91%BD%E4%BB%A4%0A%E4%BD%BF%E7%94%A8%20export%20%E5%91%BD%E4%BB%A4%E5%AE%9A%E4%B9%89%E4%BA%86%E6%A8%A1%E5%9D%97%E7%9A%84%E5%AF%B9%E5%A4%96%E6%8E%A5%E5%8F%A3%E4%BB%A5%E5%90%8E%EF%BC%8C%E5%85%B6%E4%BB%96%20JS%20%E6%96%87%E4%BB%B6%E5%B0%B1%E5%8F%AF%E4%BB%A5%E9%80%9A%0A%E8%BF%87%20import%20%E5%91%BD%E4%BB%A4%E5%8A%A0%E8%BD%BD%E8%BF%99%E4%B8%AA%E6%A8%A1%E5%9D%97%E3%80%82%0A%60%60%60js%0A%2F%2F%20main.js%0Aimport%20%7BfirstName%2C%20lastName%2C%20year%7D%20from%20'.%2Fprofile'%3B%0Afunction%20setName(element)%20%7B%0A%20%20element.textContent%20%3D%20firstName%20%2B%20'%20'%20%2B%20lastName%3B%0A%7D%0A%60%60%60%0A%0A%E5%A6%82%E6%9E%9C%E6%83%B3%E4%B8%BA%E8%BE%93%E5%85%A5%E7%9A%84%E5%8F%98%E9%87%8F%E9%87%8D%E6%96%B0%E5%8F%96%E4%B8%80%E4%B8%AA%E5%90%8D%E5%AD%97%EF%BC%8C%20import%20%E5%91%BD%E4%BB%A4%E8%A6%81%E4%BD%BF%E7%94%A8%20as%20%E5%85%B3%E9%94%AE%20%E5%AD%97%EF%BC%8C%E5%B0%86%E8%BE%93%E5%85%A5%E7%9A%84%E5%8F%98%E9%87%8F%E9%87%8D%E5%91%BD%E5%90%8D%E3%80%82%0A%60%60%60js%0Aimport%20%7B%20lastName%20as%20surname%20%7D%20from%20'.%2Fprofile'%3B%0A%60%60%60%0A%0Aimport%20%E5%91%BD%E4%BB%A4%E5%85%B7%E6%9C%89%E6%8F%90%E5%8D%87%E6%95%88%E6%9E%9C%EF%BC%8C%E4%BC%9A%E6%8F%90%E5%8D%87%E5%88%B0%E6%95%B4%E4%B8%AA%E6%A8%A1%E5%9D%97%E7%9A%84%E5%A4%B4%E9%83%A8%EF%BC%8C%E9%A6%96%E5%85%88%E6%89%A7%E8%A1%8C%E3%80%82%0A%60%60%60js%0Afoo()%3B%0Aimport%20%7B%20foo%20%7D%20from%20'my_module'%3B%0A%60%60%60%0A%0A%E7%9B%AE%E5%89%8D%E9%98%B6%E6%AE%B5%EF%BC%8C%E9%80%9A%E8%BF%87%20Babel%20%E8%BD%AC%E7%A0%81%EF%BC%8CCommonJS%20%E6%A8%A1%E5%9D%97%E7%9A%84%20require%20%E5%91%BD%E4%BB%A4%E5%92%8C%20ES6%20%E6%A8%A1%20%E5%9D%97%E7%9A%84%20import%20%E5%91%BD%E4%BB%A4%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%86%99%E5%9C%A8%E5%90%8C%E4%B8%80%E4%B8%AA%E6%A8%A1%E5%9D%97%E9%87%8C%E9%9D%A2%EF%BC%8C**%E4%BD%86%E6%98%AF%E6%9C%80%E5%A5%BD%E4%B8%8D%E8%A6%81%E8%BF%99%E6%A0%B7%E5%81%9A**%E3%80%82%20%E5%9B%A0%E4%B8%BA%20import%20%E5%9C%A8%E9%9D%99%E6%80%81%E8%A7%A3%E6%9E%90%E9%98%B6%E6%AE%B5%E6%89%A7%E8%A1%8C%EF%BC%8C%E6%89%80%E4%BB%A5%E5%AE%83%E6%98%AF%E4%B8%80%E4%B8%AA%E6%A8%A1%E5%9D%97%E4%B9%8B%E4%B8%AD%E6%9C%80%E6%97%A9%E6%89%A7%E8%A1%8C%20%E7%9A%84%E3%80%82%E4%B8%8B%E9%9D%A2%E7%9A%84%E4%BB%A3%E7%A0%81%E5%8F%AF%E8%83%BD%E4%B8%8D%E4%BC%9A%E5%BE%97%E5%88%B0%E9%A2%84%E6%9C%9F%E7%BB%93%E6%9E%9C%E3%80%82%0A%60%60%60js%0Arequire('core-js%2Fmodules%2Fes6.symbol')%3B%0Arequire('core-js%2Fmodules%2Fes6.promise')%3B%0Aimport%20React%20from%20'React'%3B%0A%60%60%60%0A%0A%23%23%23%23%20%E6%A8%A1%E5%9D%97%E7%9A%84%E6%95%B4%E4%BD%93%E5%8A%A0%E8%BD%BD%0A%0A%E9%99%A4%E4%BA%86%E6%8C%87%E5%AE%9A%E5%8A%A0%E8%BD%BD%E6%9F%90%E4%B8%AA%E8%BE%93%E5%87%BA%E5%80%BC%EF%BC%8C%E8%BF%98%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E6%95%B4%E4%BD%93%E5%8A%A0%E8%BD%BD%EF%BC%8C%E5%8D%B3%E7%94%A8%E6%98%9F%E5%8F%B7(%20*%20)%E6%8C%87%E5%AE%9A%20%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%EF%BC%8C%E6%89%80%E6%9C%89%E8%BE%93%E5%87%BA%E5%80%BC%E9%83%BD%E5%8A%A0%E8%BD%BD%E5%9C%A8%E8%BF%99%E4%B8%AA%E5%AF%B9%E8%B1%A1%E4%B8%8A%E9%9D%A2%E3%80%82%0A%60%60%60js%0A%2F%2F%20circle.js%0Aexport%20function%20area(radius)%20%7B%0A%20%20return%20Math.PI%20*%20radius%20*%20radius%3B%0A%7D%0Aexport%20function%20circumference(radius)%20%7B%0A%20%20return%202%20*%20Math.PI%20*%20radius%3B%0A%7D%0A%0A%2F%2F%E9%80%90%E4%B8%80%E6%8C%87%E5%AE%9A%E8%A6%81%E5%8A%A0%E8%BD%BD%E7%9A%84%E6%96%B9%E6%B3%95%0A%2F%2F%20main.js%0Aimport%20%7B%20area%2C%20circumference%20%7D%20from%20'.%2Fcircle'%3B%0Aconsole.log('%E5%9C%86%E9%9D%A2%E7%A7%AF%3A'%20%2B%20area(4))%3B%20console.log('%E5%9C%86%E5%91%A8%E9%95%BF%3A'%20%2B%20circumference(14))%3B%0A%0A%2F%2F%E6%95%B4%E4%BD%93%E5%8A%A0%E8%BD%BD%0Aimport%20*%20as%20circle%20from%20'.%2Fcircle'%3B%0Aconsole.log('%E5%9C%86%E9%9D%A2%E7%A7%AF%3A'%20%2B%20circle.area(4))%3B%20console.log('%E5%9C%86%E5%91%A8%E9%95%BF%3A'%20%2B%20circle.circumference(14))%3B%0A%60%60%60%0A%0A%E6%A8%A1%E5%9D%97%E6%95%B4%E4%BD%93%E5%8A%A0%E8%BD%BD%E6%89%80%E5%9C%A8%E7%9A%84%E9%82%A3%E4%B8%AA%E5%AF%B9%E8%B1%A1(%E4%B8%8A%E4%BE%8B%E6%98%AF%20circle%20)%EF%BC%8C%E5%BA%94%E8%AF%A5%E6%98%AF%E5%8F%AF%E4%BB%A5%20%E9%9D%99%E6%80%81%E5%88%86%E6%9E%90%E7%9A%84%EF%BC%8C%E6%89%80%E4%BB%A5%E4%B8%8D%E5%85%81%E8%AE%B8%E8%BF%90%E8%A1%8C%E6%97%B6%E6%94%B9%E5%8F%98%E3%80%82%E4%B8%8B%E9%9D%A2%E7%9A%84%E5%86%99%E6%B3%95%E9%83%BD%E6%98%AF%E4%B8%8D%E5%85%81%E8%AE%B8%E7%9A%84%E3%80%82%0A%60%60%60js%0Aimport%20*%20as%20circle%20from%20'.%2Fcircle'%3B%0A%2F%2F%20%E4%B8%8B%E9%9D%A2%E4%B8%A4%E8%A1%8C%E9%83%BD%E6%98%AF%E4%B8%8D%E5%85%81%E8%AE%B8%E7%9A%84%0Acircle.foo%20%3D%20'hello'%3B%0Acircle.area%20%3D%20function%20()%20%7B%7D%3B%0A%60%60%60%0A%0A%23%23%23%23%20export%20default%20%E5%91%BD%E4%BB%A4%0Aexport%20default%20%E5%91%BD%E4%BB%A4%EF%BC%8C%E4%B8%BA%E6%A8%A1%E5%9D%97%E6%8C%87%E5%AE%9A%E9%BB%98%E8%AE%A4%E8%BE%93%E5%87%BA%E3%80%82%0A%E5%85%B6%E4%BB%96%E6%A8%A1%E5%9D%97%E5%8A%A0%E8%BD%BD%E8%AF%A5%E6%A8%A1%E5%9D%97%E6%97%B6%EF%BC%8C%20import%20%E5%91%BD%E4%BB%A4%E5%8F%AF%E4%BB%A5%E4%B8%BA%E8%AF%A5%E5%8C%BF%E5%90%8D%E5%87%BD%E6%95%B0%E6%8C%87%E5%AE%9A%E4%BB%BB%E6%84%8F%E5%90%8D%20%E5%AD%97%E3%80%82%0A%60%60%60js%0A%2F%2F%20export-default.js%0Aexport%20default%20function%20()%20%7B%0A%20%20console.log('foo')%3B%0A%7D%0A%0A%2F%2F%20import-default.js%0A%2F%2F%E8%BF%99%E6%97%B6%E5%B0%B1%E4%B8%8D%E9%9C%80%E8%A6%81%E7%9F%A5%E9%81%93%E5%8E%9F%E6%A8%A1%E5%9D%97%E8%BE%93%E5%87%BA%E7%9A%84%E5%87%BD%E6%95%B0%E5%90%8D%E3%80%82%E9%9C%80%E8%A6%81%E6%B3%A8%E6%84%8F%E7%9A%84%E6%98%AF%EF%BC%8C%E8%BF%99%E6%97%B6%20import%20%E5%91%BD%E4%BB%A4%E5%90%8E%E9%9D%A2%EF%BC%8C%E4%B8%8D%E4%BD%BF%E7%94%A8%E5%A4%A7%E6%8B%AC%E5%8F%B7%E3%80%82%0Aimport%20customName%20from%20'.%2Fexport-default'%3B%0AcustomName()%3B%20%2F%2F%20'foo'%0A%60%60%60%0A%0A%E6%9C%AC%E8%B4%A8%E4%B8%8A%EF%BC%8C%20export%20default%20%E5%B0%B1%E6%98%AF%E8%BE%93%E5%87%BA%E4%B8%80%E4%B8%AA%E5%8F%AB%E5%81%9A%20default%20%E7%9A%84%E5%8F%98%E9%87%8F%E6%88%96%E6%96%B9%20%E6%B3%95%EF%BC%8C%E7%84%B6%E5%90%8E%E7%B3%BB%E7%BB%9F%E5%85%81%E8%AE%B8%E4%BD%A0%E4%B8%BA%E5%AE%83%E5%8F%96%E4%BB%BB%E6%84%8F%E5%90%8D%E5%AD%97%E3%80%82%E6%89%80%E4%BB%A5%EF%BC%8C%E4%B8%8B%E9%9D%A2%E7%9A%84%E5%86%99%E6%B3%95%E6%98%AF%E6%9C%89%E6%95%88%E7%9A%84%E3%80%82%0A%60%60%60js%0A%2F%2F%20modules.js%0Afunction%20add(x%2C%20y)%20%7B%0Areturn%20x%20*%20y%3B%20%7D%0Aexport%20%7Badd%20as%20default%7D%3B%20%2F%2F%20%E7%AD%89%E5%90%8C%E4%BA%8E%0A%2F%2F%20export%20default%20add%3B%0A%2F%2F%20app.js%0Aimport%20%7B%20default%20as%20foo%20%7D%20from%20'modules'%3B%20%2F%2F%20%E7%AD%89%E5%90%8C%E4%BA%8E%0A%2F%2F%20import%20foo%20from%20'modules'%3B%0A%60%60%60%0A%0A%E6%AD%A3%E6%98%AF%E5%9B%A0%E4%B8%BA%20export%20default%20%E5%91%BD%E4%BB%A4%E5%85%B6%E5%AE%9E%E5%8F%AA%E6%98%AF%E8%BE%93%E5%87%BA%E4%B8%80%E4%B8%AA%E5%8F%AB%E5%81%9A%20default%20%E7%9A%84%E5%8F%98%20%E9%87%8F%EF%BC%8C%E6%89%80%E4%BB%A5%E5%AE%83%E5%90%8E%E9%9D%A2%E4%B8%8D%E8%83%BD%E8%B7%9F%E5%8F%98%E9%87%8F%E5%A3%B0%E6%98%8E%E8%AF%AD%E5%8F%A5%E3%80%82%0A%60%60%60js%0A%2F%2F%20%E6%AD%A3%E7%A1%AE%0Aexport%20var%20a%20%3D%201%3B%0A%2F%2F%20%E6%AD%A3%E7%A1%AE%0Avar%20a%20%3D%201%3B%0Aexport%20default%20a%3B%0A%2F%2F%20%E9%94%99%E8%AF%AF%0Aexport%20default%20var%20a%20%3D%201%3B%0A%60%60%60%0A%0A%23%23%23%23%20export%20%E4%B8%8E%20import%20%E7%9A%84%E5%A4%8D%E5%90%88%E5%86%99%E6%B3%95%0A%E5%A6%82%E6%9E%9C%E5%9C%A8%E4%B8%80%E4%B8%AA%E6%A8%A1%E5%9D%97%E4%B9%8B%E4%B8%AD%EF%BC%8C%E5%85%88%E8%BE%93%E5%85%A5%E5%90%8E%E8%BE%93%E5%87%BA%E5%90%8C%E4%B8%80%E4%B8%AA%E6%A8%A1%E5%9D%97%EF%BC%8C%20import%20%E8%AF%AD%E5%8F%A5%E5%8F%AF%E4%BB%A5%0A%E4%B8%8E%20export%20%E8%AF%AD%E5%8F%A5%E5%86%99%E5%9C%A8%E4%B8%80%E8%B5%B7%E3%80%82%0A%60%60%60js%0Aexport%20%7B%20foo%2C%20bar%20%7D%20from%20'my_module'%3B%0A%2F%2F%20%E7%AD%89%E5%90%8C%E4%BA%8E%0Aimport%20%7B%20foo%2C%20bar%20%7D%20from%20'my_module'%3B%0Aexport%20%7B%20foo%2C%20bar%20%7D%3B%0A%0A%2F%2F%20%E6%8E%A5%E5%8F%A3%E6%94%B9%E5%90%8D%0Aexport%20%7B%20foo%20as%20myFoo%20%7D%20from%20'my_module'%3B%0A%2F%2F%20%E6%95%B4%E4%BD%93%E8%BE%93%E5%87%BA%0Aexport%20*%20from%20'my_module'%3B%0A%0A%2F%2F%E9%BB%98%E8%AE%A4%E6%8E%A5%E5%8F%A3%E7%9A%84%E5%86%99%E6%B3%95%E5%A6%82%E4%B8%8B%0Aexport%20%7B%20default%20%7D%20from%20'foo'%3B%0A%0A%2F%2F%E5%85%B7%E5%90%8D%E6%8E%A5%E5%8F%A3%E6%94%B9%E4%B8%BA%E9%BB%98%E8%AE%A4%E6%8E%A5%E5%8F%A3%E7%9A%84%E5%86%99%E6%B3%95%E5%A6%82%E4%B8%8B%0Aexport%20%7B%20es6%20as%20default%20%7D%20from%20'.%2FsomeModule'%3B%0A%2F%2F%20%E7%AD%89%E5%90%8C%E4%BA%8E%0Aimport%20%7B%20es6%20%7D%20from%20'.%2FsomeModule'%3B%0Aexport%20default%20es6%3B%0A%0Aexport%20%7B%20default%20as%20es6%20%7D%20from%20'.%2FsomeModule'%3B%0A%0A%2F%2F%E4%B8%8B%E9%9D%A2%E4%B8%89%E7%A7%8D%20import%20%E8%AF%AD%E5%8F%A5%EF%BC%8C%E6%B2%A1%E6%9C%89%E5%AF%B9%E5%BA%94%E7%9A%84%E5%A4%8D%E5%90%88%E5%86%99%E6%B3%95%E3%80%82%0Aimport%20*%20as%20someIdentifier%20from%20%22someModule%22%3B%0Aimport%20someIdentifier%20from%20%22someModule%22%3B%0Aimport%20someIdentifier%2C%20%7B%20namedIdentifier%20%7D%20from%0A%22someModule%22%3B%0A%60%60%60%0A%0A%23%23%23%23%20%E6%A8%A1%E5%9D%97%E7%9A%84%E7%BB%A7%E6%89%BF%0A%E6%A8%A1%E5%9D%97%E4%B9%8B%E9%97%B4%E4%B9%9F%E5%8F%AF%E4%BB%A5%E7%BB%A7%E6%89%BF%E3%80%82%0A%E5%81%87%E8%AE%BE%E6%9C%89%E4%B8%80%E4%B8%AA%20circleplus%20%E6%A8%A1%E5%9D%97%EF%BC%8C%E7%BB%A7%E6%89%BF%E4%BA%86%20circle%20%E6%A8%A1%E5%9D%97%E3%80%82%0A%60%60%60js%0A%2F%2F%20circleplus.js%0Aexport%20*%20from%20'circle'%3B%0Aexport%20var%20e%20%3D%202.71828182846%3B%0Aexport%20default%20function(x)%20%7B%0A%20%20return%20Math.exp(x)%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%20%E8%B7%A8%E6%A8%A1%E5%9D%97%E5%B8%B8%E9%87%8F%0A%20const%20%E5%A3%B0%E6%98%8E%E7%9A%84%E5%B8%B8%E9%87%8F%E5%8F%AA%E5%9C%A8%E5%BD%93%E5%89%8D%E4%BB%A3%E7%A0%81%E5%9D%97%20%E6%9C%89%E6%95%88%E3%80%82%E5%A6%82%E6%9E%9C%E6%83%B3%E8%AE%BE%E7%BD%AE%E8%B7%A8%E6%A8%A1%E5%9D%97%E7%9A%84%E5%B8%B8%E9%87%8F(%E5%8D%B3%E8%B7%A8%E5%A4%9A%E4%B8%AA%E6%96%87%E4%BB%B6)%EF%BC%8C%E6%88%96%E8%80%85%E8%AF%B4%E4%B8%80%E4%B8%AA%E5%80%BC%E8%A6%81%E8%A2%AB%20%E5%A4%9A%E4%B8%AA%E6%A8%A1%E5%9D%97%E5%85%B1%E4%BA%AB%EF%BC%8C%E5%8F%AF%E4%BB%A5%E9%87%87%E7%94%A8%E4%B8%8B%E9%9D%A2%E7%9A%84%E5%86%99%E6%B3%95%E3%80%82%0A%60%60%60js%0A%2F%2F%20constants.js%20%E6%A8%A1%E5%9D%97%0Aexport%20const%20A%20%3D%201%3B%0Aexport%20const%20B%20%3D%203%3B%0Aexport%20const%20C%20%3D%204%3B%0A%2F%2F%20test1.js%20%E6%A8%A1%E5%9D%97%0Aimport%20*%20as%20constants%20from%20'.%2Fconstants'%3B%0Aconsole.log(constants.A)%3B%20%2F%2F%201%0Aconsole.log(constants.B)%3B%20%2F%2F%203%0A%2F%2F%20test2.js%20%E6%A8%A1%E5%9D%97%0Aimport%20%7BA%2C%20B%7D%20from%20'.%2Fconstants'%3B%0Aconsole.log(A)%3B%20%2F%2F%201%0Aconsole.log(B)%3B%20%2F%2F%203%0A%60%60%60%0A%0A%E5%A6%82%E6%9E%9C%E8%A6%81%E4%BD%BF%E7%94%A8%E7%9A%84%E5%B8%B8%E9%87%8F%E9%9D%9E%E5%B8%B8%E5%A4%9A%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%BB%BA%E4%B8%80%E4%B8%AA%E4%B8%93%E9%97%A8%E7%9A%84%20constants%20%E7%9B%AE%E5%BD%95%EF%BC%8C%E5%B0%86%E5%90%84%20%E7%A7%8D%E5%B8%B8%E9%87%8F%E5%86%99%E5%9C%A8%E4%B8%8D%E5%90%8C%E7%9A%84%E6%96%87%E4%BB%B6%E9%87%8C%E9%9D%A2%EF%BC%8C%E4%BF%9D%E5%AD%98%E5%9C%A8%E8%AF%A5%E7%9B%AE%E5%BD%95%E4%B8%8B%E3%80%82%0A%60%60%60js%0A%2F%2F%20constants%2Fdb.js%0Aexport%20const%20db%20%3D%20%7B%0A%20%20url%3A%20'http%3A%2F%2Fmy.couchdbserver.local%3A5984'%2C%0A%20%20admin_username%3A%20'admin'%2C%0A%20%20admin_password%3A%20'admin%20password'%0A%7D%3B%0A%2F%2F%20constants%2Fuser.js%0Aexport%20const%20users%20%3D%20%5B'root'%2C%20'admin'%2C%20'staff'%2C%20'ceo'%2C%0A'chief'%2C%20'moderator'%5D%3B%0A%0A%2F%2F%E7%84%B6%E5%90%8E%EF%BC%8C%E5%B0%86%E8%BF%99%E4%BA%9B%E6%96%87%E4%BB%B6%E8%BE%93%E5%87%BA%E7%9A%84%E5%B8%B8%E9%87%8F%EF%BC%8C%E5%90%88%E5%B9%B6%E5%9C%A8%20index.js%20%E9%87%8C%E9%9D%A2%E3%80%82%0A%2F%2F%20constants%2Findex.js%0Aexport%20%7Bdb%7D%20from%20'.%2Fdb'%3B%0Aexport%20%7Busers%7D%20from%20'.%2Fusers'%3B%0A%0A%2F%2F%E4%BD%BF%E7%94%A8%E7%9A%84%E6%97%B6%E5%80%99%EF%BC%8C%E7%9B%B4%E6%8E%A5%E5%8A%A0%E8%BD%BD%20index.js%20%E5%B0%B1%E5%8F%AF%E4%BB%A5%E4%BA%86%E3%80%82%0A%2F%2F%20script.js%0Aimport%20%7Bdb%2C%20users%7D%20from%20'.%2Findex'%3B%0A%60%60%60%0A%0A%23%23%23%23%20import()%0Aimport%20%E5%92%8C%20export%20%E5%91%BD%E4%BB%A4%20%E5%8F%AA%E8%83%BD%E5%9C%A8%E6%A8%A1%E5%9D%97%E7%9A%84%E9%A1%B6%E5%B1%82%EF%BC%8C%E4%B8%8D%E8%83%BD%E5%9C%A8%E4%BB%A3%E7%A0%81%E5%9D%97%E4%B9%8B%E4%B8%AD(%E6%AF%94%E5%A6%82%EF%BC%8C%E5%9C%A8%20if%20%E4%BB%A3%E7%A0%81%E5%9D%97%E4%B9%8B%E4%B8%AD%EF%BC%8C%E6%88%96%20%E5%9C%A8%E5%87%BD%E6%95%B0%E4%B9%8B%E4%B8%AD)%E3%80%82%E5%AF%BC%E8%87%B4%E6%97%A0%E6%B3%95%E5%9C%A8%E8%BF%90%E8%A1%8C%E6%97%B6%E5%8A%A0%E8%BD%BD%E6%A8%A1%E5%9D%97%E3%80%82%E5%9C%A8%E8%AF%AD%E6%B3%95%E4%B8%8A%EF%BC%8C%E6%9D%A1%E4%BB%B6%E5%8A%A0%E8%BD%BD%E5%B0%B1%E4%B8%8D%E5%8F%AF%E8%83%BD%E5%AE%9E%E7%8E%B0%E3%80%82%E5%A6%82%E6%9E%9C%20import%20%E5%91%BD%E4%BB%A4%E8%A6%81%E5%8F%96%E4%BB%A3%20Node%20%E7%9A%84%20require%20%E6%96%B9%E6%B3%95%EF%BC%8C%E8%BF%99%E5%B0%B1%E5%BD%A2%E6%88%90%E4%BA%86%E4%B8%80%E4%B8%AA%E9%9A%9C%E7%A2%8D%E3%80%82%E5%9B%A0%E4%B8%BA%20require%20%E6%98%AF%E8%BF%90%E8%A1%8C%20%E6%97%B6%E5%8A%A0%E8%BD%BD%E6%A8%A1%E5%9D%97%EF%BC%8C%20import%20%E5%91%BD%E4%BB%A4%E6%97%A0%E6%B3%95%E5%8F%96%E4%BB%A3%20require%20%E7%9A%84%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E5%8A%9F%E8%83%BD%E3%80%82%0A%E5%9B%A0%E6%AD%A4%EF%BC%8C%E6%9C%89%E4%B8%80%E4%B8%AA%E6%8F%90%E6%A1%88%EF%BC%8C%E5%BB%BA%E8%AE%AE%E5%BC%95%E5%85%A5%20import()%20%E5%87%BD%E6%95%B0%EF%BC%8C%E5%AE%8C%E6%88%90%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E3%80%82%0A%0Aimport%20%E5%91%BD%E4%BB%A4%E8%83%BD%E5%A4%9F%E6%8E%A5%E5%8F%97%E4%BB%80%E4%B9%88%E5%8F%82%E6%95%B0%EF%BC%8C%20import()%20%E5%87%BD%E6%95%B0%E5%B0%B1%E8%83%BD%E6%8E%A5%E5%8F%97%E4%BB%80%20%E4%B9%88%E5%8F%82%E6%95%B0%EF%BC%8C%E4%B8%A4%E8%80%85%E5%8C%BA%E5%88%AB%E4%B8%BB%E8%A6%81%E6%98%AF%E5%90%8E%E8%80%85%E4%B8%BA%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E3%80%82%0Aimport()%20%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%20Promise%20%E5%AF%B9%E8%B1%A1%E3%80%82%0A%60%60%60js%0Aconst%20main%20%3D%20document.querySelector('main')%3B%0Aimport(%60.%2Fsection-modules%2F%24%7BsomeVariable%7D.js%60)%0A%20%20.then(module%20%3D%3E%20%7B%0A%20%20%20%20module.loadPageInto(main)%3B%0A%20%20%7D)%0A%20%20.catch(err%20%3D%3E%20%7B%0A%20%20%20%20main.textContent%20%3D%20err.message%3B%0A%7D)%3B%0A%60%60%60%0A%0Aimport()%20%E5%87%BD%E6%95%B0%E5%8F%AF%E4%BB%A5%E7%94%A8%E5%9C%A8%E4%BB%BB%E4%BD%95%E5%9C%B0%E6%96%B9%EF%BC%8C%E4%B8%8D%E4%BB%85%E4%BB%85%E6%98%AF%E6%A8%A1%E5%9D%97%EF%BC%8C%E9%9D%9E%E6%A8%A1%E5%9D%97%E7%9A%84%E8%84%9A%E6%9C%AC%E4%B9%9F%E5%8F%AF%20%E4%BB%A5%E4%BD%BF%E7%94%A8%E3%80%82%E5%AE%83%E6%98%AF%E8%BF%90%E8%A1%8C%E6%97%B6%E6%89%A7%E8%A1%8C%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%EF%BC%8C%E4%BB%80%E4%B9%88%E6%97%B6%E5%80%99%E8%BF%90%E8%A1%8C%E5%88%B0%E8%BF%99%E4%B8%80%E5%8F%A5%EF%BC%8C%E4%B9%9F%E4%BC%9A%E5%8A%A0%20%E8%BD%BD%E6%8C%87%E5%AE%9A%E7%9A%84%E6%A8%A1%E5%9D%97%E3%80%82%E5%8F%A6%E5%A4%96%EF%BC%8C%20import()%20%E5%87%BD%E6%95%B0%E4%B8%8E%E6%89%80%E5%8A%A0%E8%BD%BD%E7%9A%84%E6%A8%A1%E5%9D%97%E6%B2%A1%E6%9C%89%E9%9D%99%E6%80%81%E8%BF%9E%E6%8E%A5%E5%85%B3%20%E7%B3%BB%EF%BC%8C%E8%BF%99%E7%82%B9%E4%B9%9F%E6%98%AF%E4%B8%8E%20import%20%E8%AF%AD%E5%8F%A5%E4%B8%8D%E7%9B%B8%E5%90%8C%E3%80%82%0Aimport()%20%E7%B1%BB%E4%BC%BC%E4%BA%8E%20Node%20%E7%9A%84%20require%20%E6%96%B9%E6%B3%95%EF%BC%8C%E5%8C%BA%E5%88%AB%E4%B8%BB%E8%A6%81%E6%98%AF%E5%89%8D%E8%80%85%E6%98%AF%E5%BC%82%E6%AD%A5%E5%8A%A0%20%E8%BD%BD%EF%BC%8C%E5%90%8E%E8%80%85%E6%98%AF%E5%90%8C%E6%AD%A5%E5%8A%A0%E8%BD%BD%E3%80%82%0A%0A%23%23%23%23%23%20%E9%80%82%E7%94%A8%E5%9C%BA%E5%90%88%0A%0A(1)%E6%8C%89%E9%9C%80%E5%8A%A0%E8%BD%BD%E3%80%82%0A(2)%E6%9D%A1%E4%BB%B6%E5%8A%A0%E8%BD%BD%E3%80%82%0A(3)%E5%8A%A8%E6%80%81%E7%9A%84%E6%A8%A1%E5%9D%97%E8%B7%AF%E5%BE%84%E3%80%82%0A%60%60%60js%0A%2F%2F%E6%A0%B9%E6%8D%AE%E5%87%BD%E6%95%B0%20f%20%E7%9A%84%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%EF%BC%8C%E5%8A%A0%E8%BD%BD%E4%B8%8D%E5%90%8C%E7%9A%84%E6%A8%A1%E5%9D%97%E3%80%82%0Aimport(f())%0A.then(...)%3B%0A%60%60%60%0A%0A%23%23%23%23%23%20%E6%B3%A8%E6%84%8F%E7%82%B9%0Aimport()%20%E5%8A%A0%E8%BD%BD%E6%A8%A1%E5%9D%97%E6%88%90%E5%8A%9F%E4%BB%A5%E5%90%8E%EF%BC%8C%E8%BF%99%E4%B8%AA%E6%A8%A1%E5%9D%97%E4%BC%9A%E4%BD%9C%E4%B8%BA%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%EF%BC%8C%E5%BD%93%0A%E4%BD%9C%20then%20%E6%96%B9%E6%B3%95%E7%9A%84%E5%8F%82%E6%95%B0%E3%80%82%E5%9B%A0%E6%AD%A4%EF%BC%8C%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E5%AF%B9%E8%B1%A1%E8%A7%A3%E6%9E%84%E8%B5%8B%E5%80%BC%E7%9A%84%E8%AF%AD%E6%B3%95%EF%BC%8C%E8%8E%B7%E5%8F%96%E8%BE%93%E5%87%BA%20%E6%8E%A5%E5%8F%A3%E3%80%82%0A%60%60%60js%0Aimport('.%2FmyModule.js')%0A.then((%7Bexport1%2C%20export2%7D)%20%3D%3E%20%7B%0A%2F%2F%20...%C2%B7%0A%7D)%3B%0A%0A%2F%2F%E5%A6%82%E6%9E%9C%E6%A8%A1%E5%9D%97%E6%9C%89%20default%20%E8%BE%93%E5%87%BA%E6%8E%A5%E5%8F%A3%EF%BC%8C%E5%8F%AF%E4%BB%A5%E7%94%A8%E5%8F%82%E6%95%B0%E7%9B%B4%E6%8E%A5%E8%8E%B7%E5%BE%97%0Aimport('.%2FmyModule.js')%0A.then(myModule%20%3D%3E%20%7B%0A%20%20console.log(myModule.default)%3B%0A%7D)%3B%0A%0A%2F%2F%E4%B8%8A%E9%9D%A2%E7%9A%84%E4%BB%A3%E7%A0%81%E4%B9%9F%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E5%85%B7%E5%90%8D%E8%BE%93%E5%85%A5%E7%9A%84%E5%BD%A2%E5%BC%8F%E3%80%82%0Aimport('.%2FmyModule.js')%0A.then((%7Bdefault%3A%20theDefault%7D)%20%3D%3E%20%7B%0A%20%20console.log(theDefault)%3B%0A%7D)%3B%0A%0A%2F%2F%E5%A6%82%E6%9E%9C%E6%83%B3%E5%90%8C%E6%97%B6%E5%8A%A0%E8%BD%BD%E5%A4%9A%E4%B8%AA%E6%A8%A1%E5%9D%97%EF%BC%8C%E5%8F%AF%E4%BB%A5%E9%87%87%E7%94%A8%E4%B8%8B%E9%9D%A2%E7%9A%84%E5%86%99%E6%B3%95%E3%80%82%0APromise.all(%5B%0A%20%20import('.%2Fmodule1.js')%2C%0A%20%20import('.%2Fmodule2.js')%2C%0A%20%20import('.%2Fmodule3.js')%2C%0A%5D)%0A.then((%5Bmodule1%2C%20module2%2C%20module3%5D)%20%3D%3E%20%7B%0A%C2%B7%C2%B7%C2%B7%20%7D)%3B%0A%0A%2F%2Fimport()%20%E4%B9%9F%E5%8F%AF%E4%BB%A5%E7%94%A8%E5%9C%A8%20async%20%E5%87%BD%E6%95%B0%E4%B9%8B%E4%B8%AD%E3%80%82%0Aasync%20function%20main()%20%7B%0A%20%20const%20myModule%20%3D%20await%20import('.%2FmyModule.js')%3B%0A%20%20const%20%7Bexport1%2C%20export2%7D%20%3D%20await%0Aimport('.%2FmyModule.js')%3B%0A%20%20const%20%5Bmodule1%2C%20module2%2C%20module3%5D%20%3D%0A%20%20%20%20await%20Promise.all(%5B%0A%20%20%20%20%20%20import('.%2Fmodule1.js')%2C%0A%20%20%20%20%20%20import('.%2Fmodule2.js')%2C%0A%20%20%20%20%20%20import('.%2Fmodule3.js')%2C%0A%5D)%3B%20%7D%0Amain()%3B%0A%60%60%60</center></body></html>